vwkd
12/02/2025, 1:25 AMuserData to the category handler. However, since a URL is only scraped once, only the first category gets saved and all others discarded.
Here's a minimal example.
ts
import { Router } from "crawlee";
export const router = Router.create();
// ... other handlers
// imagine the category handler is called twice
router.addHandler("CATEGORY", async ({ enqueueLinks }) => {
// ... parsing
// result of first call
await enqueueLinks({
urls: ["https://example.com/my-product"],
userData: { category: "foo" },
label: "DETAIL",
});
// result of second call
await enqueueLinks({
urls: ["https://example.com/my-product"],
userData: { category: "bar" },
label: "DETAIL",
});
});
router.addHandler("DETAIL", async ({ request }) => {
// todo: how to get both "foo" and "bar" here?
const category = request.userData.category;
// ... saving
});Answer Overflow
12/02/2025, 1:25 AMPepa J
12/05/2025, 10:18 AMuseState to store the information and load the information withing multiple crawler instances:
js
import { useState } from 'crawlee';
// initialization categoryRouter, defaultRouter, categoryRequestQueue, detailRequestQueue
categoryRouter.addHandler("CATEGORY", async ({ enqueueLinks, crawler }) => {
const categoryName = ...;
const productCategories = await Actor.useState('productCategories', {}); // shared state
const detailUrls = await page.$$eval('.product-detail a', (linkElements) => linkElements.map((linkEl) => linkEl.href)
for (const detailUrl of detailUrls) {
productCategories[detailUrl] ??= [];
productCategories[detailUrl].push(categoryName);
}
// ...add product detail urls to the detailRequestQueue
});
detailRouter.addHandler("DETAIL", async ({ request }) => {
const productCategories = await Actor.useState('productCategories', {});
const categories = productCategories[request.url];
// ... saving
});
Let me know if that makes sense.