https://apify.com/ logo
Join Discord
Powered by
  • “BasicCrawler vs CheerioCrawler for local Electron app (custom HTTPS fetch)”
    a

    Answer Overflow

    10/07/2026, 7:34 PM
    message has been deleted
    0
  • Please feel free to contact me anytime if you need a developer.
    f

    Fukami

    09/21/2026, 8:56 AM
    Please feel free to contact me anytime if you need a developer.
    0
    a
    • 2
    • 1
  • How to cleanly cancel/abort a queued request before network call & handler without triggering error
    f

    fierDeToiMonGrand

    08/30/2026, 1:12 AM
    Hey everyone! I'm using
    CheerioCrawler
    and need a way to conditionally drop/abort requests that are already in the
    RequestQueue
    when a runtime condition is met. The goal is to completely discard the request so it: - Does not make the network request. - Does not execute the
    requestHandler
    . - Does not count as a failed request or log an error. ## What I tried ### 1. Throwing a custom error in
    preNavigationHooks
    Copy code
    ts
    preNavigationHooks: [
      async ({ request }) => {
        if (shouldAbortRequest(request)) {
          request.noRetry = true;
          throw new CustomAbortError();
        }
      },
    ]
    I also swallow the error in
    errorHandler
    and
    failedRequestHandler
    . Problem: Crawlee still marks the request as FAILED, logs
    Request failed and reached maximum retries
    , and increments failed request metrics. ### 2. Using
    request.skipNavigation = true
    Copy code
    ts
    preNavigationHooks: [
      async ({ request }) => {
        if (shouldAbortRequest(request)) {
          request.skipNavigation = true;
        }
      },
    ]
    Problem: This skips the HTTP request, but
    requestHandler
    still executes unless I add manual guard logic. ## Question Is there an official/idiomatic way to completely cancel an enqueued request so it is silently discarded without: - Making the network request. - Running the route/request handler. - Being treated as a failed request. Thanks!
    0
    a
    a
    f
    • 4
    • 9
  • How to Avoid Duplicate Leads When Using Apify for Long-Term Lead Generation?
    v

    VFactoriel

    08/13/2026, 7:46 AM
    Hey, I have a question about using Apify for long-term lead generation. I'm planning to use Apify to fetch around 1,000 leads per day based on specific locations and job positions. I expect to run this process continuously for about 4–5 months to build and enrich my database. My main concern is duplicate profiles across different runs. For example, let's say I've already collected 10,000 profiles. The next day, I request another 1,000 profiles matching the same criteria. How does Apify ensure that those 1,000 results haven't already been returned in previous runs? If 900 of those profiles are duplicates and only 100 are new, I would effectively be paying for 1,000 results while only adding 100 new leads to my database. Is there a built-in mechanism to prevent previously retrieved profiles from being fetched again across multiple runs? Ideally, I would like to maintain a list of already retrieved profile IDs/URLs and have Apify exclude them before scraping or charging for the results. Does Apify support something like this, or would the deduplication need to be handled on my side?
    0
    a
    f
    • 3
    • 2
  • How to send HTTP Resquest with Auth Data
    a

    Answer Overflow

    07/24/2026, 4:35 AM
    message has been deleted
    0
    e
    m
    • 3
    • 2
  • PROPBLEM Google's Instagram results
    u

    usama

    06/21/2026, 9:28 AM
    Hi everyone, Has anyone noticed a recent change in Google's Instagram results? My Apify actor uses
    0
    a
    • 2
    • 1
  • Trying to Understand Modern Rate Limiting Before Using Proxies
    c

    clairvoyant

    05/23/2026, 9:42 AM
    Been running into aggressive rate limiting while testing some crawlers and automation flows, and I’m trying to understand what modern systems are actually detecting before I jump straight to proxies as the solution. What’s interesting is that sometimes I’m getting blocked even at very low request rates, which makes me think the issue is more about request quality and session behavior than raw traffic volume. I’ve already tried things like: * slowing request frequency * rotating headers/user agents * adding delays
    0
    a
    m
    • 3
    • 2
  • Parallel crawling using both Cheerio and Playwright?
    s

    SirkFun

    04/16/2026, 12:35 PM
    Can PlaywrightCrawler and CheerioCrawler be used in parallel? For example, can Playwright push a URL (got detail page URL by javascript rendering) to CheerioCrawler request queue for another immediate crawling (get the detailed page json data)? I noticed Request Queue V2, but the official examples seem aimed at speeding up crawling via process forking. I am looking for a more lightweight approach where CheerioCrawler handles the remaining work without the two blocking each other. Do you have any insights on this?
    0
    m
    a
    • 3
    • 3
  • How to open multiple browsers
    a

    Answer Overflow

    02/27/2026, 6:50 AM
    message has been deleted
    0
    h
    m
    +4
    • 7
    • 6
  • Skipping URLs in the handler for https://domain.com/page.html due to the enqueueLinks limit of 0.
    c

    cryptorex

    02/24/2026, 6:29 PM
    As title says, not sure why we're receiving this message now, I don't want ANY urls skipped and there doesn't seem to be a way to make sure they do get re-queued? Is this benign internal tracking messaging? I upgraded from 3.13.0 -> 3.16.0 and noticed this behavior. In researching it seems like its tied to
    maxRequestsPerCrawl
    but this setting is to prevent infinite looping of certain sites. What am I missing? Current setting is
    maxRequestsPerCrawl: 20000
    Thanks.
    0
    m
    • 2
    • 2
  • Redis RequestQueue
    n

    NeoNomade | Scraping hellhound

    02/20/2026, 2:28 PM
    I see that in crawlee-python we have the option to use Redis for this, anybody figured a way to use Redis on crawlee-js (TS) ?
    0
    a
    o
    • 3
    • 3
  • Question related to camoufox-js
    t

    TsukimaJ

    02/19/2026, 6:38 AM
    Hi guys i don't know if this is the right place to ask so sorry in advance For my application having persistant context AND fingerprinting is a must and i was wondering how to properly work with it here since for every session i can easily maintain cookies/userdata but not fingerprinting , is using config on launch and applying specific fingerprint the only way to maintain fingerprint inbetween sessions? Thanks!
    0
    a
    m
    • 3
    • 3
  • Need fullstack dev urgently
    w

    Witcher King

    02/15/2026, 2:26 PM
    I’m looking for a full stack developer who can start working on our project from tomorrow. The frontend (Part 1) was done by a previous developer but not very well, so we had to pause. I need someone who’s up to date with recent tools and best practices and is skilled in backend development (preferably Node.js) and database management. This project is for a game project, and we need to build a solid paywall system and admin page. I’m looking for someone who can take the lead, handle the full development until deployment, and also prepare proper documentation. Let’s talk and see how we can work together.
    0
    a
    • 2
    • 2
  • PlaywrightCrawler not competing the jobs I added in the queue using addRequests()
    h

    Hamid Jutt

    02/11/2026, 12:41 PM
    PlaywrightCrawler not competing the jobs I added in the queue using addRequests(). I am self hosting crawlee and running playwrightCrawler and I add 100-150 requests in queue and and maxComcurrency is 12 and the crawlee don’t finish all the requests that I added. It is never started the crawler for 3 url. I try different urls different websites but it is skipping or whatever but it is no started or no pick 2-4 request from 100-150
    0
    a
    m
    a
    • 4
    • 27
  • How to configure PlaywrightCrawler or PuppeteerCrawler with Browserless?
    w

    Wei

    02/01/2026, 1:15 PM
    Hello, I have no success in setting up either of the crawlers with Browserless. What is the proper Typescript way to do that with Browserless? Any docs? Thank you! ⁨⁨```ts const crawler = new PuppeteerCrawler({ launchContext: { useChrome: true, launcher: puppeteer, launchOptions: { browserWSEndpoint: wsEndpoint, => not even connected with this option args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage' ] } }, ```⁩⁩ ⁨⁨```ts const crawler = new PlaywrightCrawler({ launchContext: { launchOptions: { browserWSEndpoint: wsEndpoint, => not even has this property }, }, ```⁩⁩
    0
    a
    l
    +3
    • 6
    • 7
  • No matter which params i change my cpu is always around 50% and ram not used more than ~20%
    m

    Michael

    01/28/2026, 1:23 PM
    Hi 🙂 , Here my code
    Copy code
    const configuration = {
      purgeOnStart: false,
      availableMemoryRatio: 0.75,
      maxMemoryOverloadedRatio: 0.75,
      maxEventLoopOverloadedRatio: 0.75,
      maxCpuOverloadedRatio: 0.75,
      maxClientOverloadedRatio: 0.7,
      desiredConcurrencyRatio: 0.5,
      persistStorage: true,
      persistStateIntervalMillis: 10000,
    }
    
    const crawler = new PlaywrightCrawler(
      {
        keepAlive: true,
        minConcurrency: 126,
        maxConcurrency: 252,
        maxRequestRetries: 5,
        requestHandlerTimeoutSecs: 10,
        proxyConfiguration,
        useSessionPool: false, // for performance and less detection must be false
        sessionPoolOptions: { maxPoolSize: 426 },
        persistCookiesPerSession: false,
    0
    a
    p
    • 3
    • 3
  • Running the same crawler in paralell
    n

    nehalist

    01/18/2026, 12:28 PM
    I've got a config file like
    Copy code
    yaml
    jobs:
      - name: "amazon.de"
        enabled: true
    
        crawler:
          id: "test"
          enabled: true
          config:
            urls:
              - "https://example.com"
    
      - name: "amazon.fr"
        enabled: true
    
        crawler:
          id: "test"
          enabled: true
          config:
            urls:
              - "https://example.com"
    this config is processed via p-queue and, depending on the crawler id, I want to run a specific crawler, e.g.:
    Copy code
    typescript
    export const testCrawler = createCrawler({
      id: "test",
    
      configSchema: z.object({
        urls: z.array(z.string()),
      }),
    
      handler: async ({ urls }) => {
        if (!crawler) {
          crawler = new PlaywrightCrawler({
            async requestHandler({ request, log }) {
              log.info(`Processing: ${request.url}`);
            },
          });
        }
        await crawler.run(urls);
      },
    });
    different sites might use the crawler but a different
    requestHandler
    . currently when running this I get > This crawler instance is already running, you can add more requests to it via
    crawler.addRequests()
    so it's not possible to spawn multiple crawlers of the same type at the same time? would kinda mess up my mental model (and the current impl) a bit. if so, I guess I need to "collect" all data before running the actual crawler? since different crawler "definitions" (e.g.
    testCrawler
    ) require different configurations, this could get messy
    0
    a
    m
    • 3
    • 3
  • Is there a type for "any crawler"?
    n

    nehalist

    01/12/2026, 9:38 PM
    I have a bunch of different crawler definitions (for different sites) that might use different crawlee crawlers. Site X might use a
    PlaywrightCrawler
    while site Y uses
    CheerioCrawler
    . I wrap this logic in a definition like
    Copy code
    class SiteXCrawlerDefinition {
      getCrawler() { return new PlaywrightCrawler() }
    }
    since I do want to add an interface to the crawler definition classes I'd need a return type for
    getCrawler
    .
    BasicCrawler
    doesn't work - is there another type for "just any crawlee crawler"?
    0
    a
    n
    • 3
    • 3
  • Newer Crawlee Versions Cause Double Request Queue Writes & Version Compatibility Issues
    f

    fierDeToiMonGrand

    01/09/2026, 8:33 PM
    I'm experiencing a critical cost issue where Crawlee 3.15.3 writes 2x more request queue operations compared to version 3.12.1 for the exact same actor and input on Apify platform. This doubles my costs, so I need to use 3.12.1, but I'm hitting compatibility issues. ### The Problem (When running locally on my machine) When trying to use
    crawlee@3.12.1
    with
    apify@^3.0.0
    (3.2.6), I encounter two blocking issues 1. TypeScript compilation error - Type mismatch in proxy configuration:
    Copy code
    typescript
    const proxyConfiguration = await Actor.createProxyConfiguration();
    const crawler = new CheerioCrawler({
      proxyConfiguration: proxyConfiguration, // ❌ Type error
      requestHandler: router,
    });
    2. Runtime error when running locally (even after ignoring TypeScript with
    as any
    ):
    Copy code
    Error: Detected incompatible Crawlee version used by the SDK.
    User installed 3.12.1 but the SDK uses 3.15.3.
        at checkCrawleeVersion (node_modules/apify/utils.js:68)
        at Actor.init (node_modules/apify/main.js:123)
    ### Why I Need 3.12.1 Specifically Cost Impact: For the same run with identical input, Crawlee 3.15.3 generates roughly double the request queue writes compared to 3.12.1: (See attached screenshot) I don't know what changed between these versions, but 3.15.3 is significantly more expensive to run. ### My Current Solution (Need Validation) To force deduplication locally and replicate Apify's behavior, I added npm overrides to package.json:
    Copy code
    json
    {
      "dependencies": {
        "apify": "^3.0.0",
        "crawlee": "3.12.1"
      },
      "overrides": {
        "@crawlee/core": "3.12.1",
        "@crawlee/types": "3.12.1",
        "@crawlee/utils": "3.12.1"
      }
    }
    ### My Questions 1. Is using npm "overrides" the correct approach here? Will this cause issues when deploying to Apify platform? 2. Why does Crawlee 3.15.3 generate 2x more request queue writes than 3.12.1? What changed between these versions that causes this cost increase? https://cdn.discordapp.com/attachments/1459284049213390930/1459284049670439085/image.png?ex=697bc42d&is=697a72ad&hm=cdbd36bd99fd062bbd4206205376088a70de3b9b6f17430b956ddad86820a2a1& https://cdn.discordapp.com/attachments/1459284049213390930/1459284050295656488/image.png?ex=697bc42d&is=697a72ad&hm=89afe8139411796d65547e38c74c182e5726b16c91336a58baa1f3bc2b4e523d&
    0
    n
    • 2
    • 3
  • Optimization: replacing addRequests with sendRequest to save Queue Writes cost—blocking concerns?
    f

    fierDeToiMonGrand

    01/07/2026, 2:53 PM
    Hey everyone, I’m trying to optimize my actor's costs. I noticed "Request Queue Writes" are eating up a huge chunk of my budget because I currently enqueue a separate request for a "Details/Enrichment" page for every single item I scrape. I want to switch to fetching these details inline using
    sendRequest
    to skip the database write costs. However, the target site is strict with blocking. My question is: If I use
    sendRequest
    inside a handler, is manually passing
    session
    and
    proxyInfo.url
    enough to maintain the exact same fingerprint/IP as the main crawler?
    I want to avoid the "Details" request looking like a fresh bot hit. Here is the pattern I'm trying to implement:
    Copy code
    typescript
    // CURRENT EXPENSIVE APPROACH:
    // Enqueues a whole new request, costing 1 Write + 1 Handled per item
    /*
    await crawler.addRequests([{
        url: detailUrl,
        label: 'EXTRA_DATA',
        userData: { ... }
    }]);
    */
    
    // PROPOSED COST-SAVING APPROACH:
    // Fetches inline to avoid touching the Request Queue DB
    router.addHandler('ITEM_PAGE', async ({ request, session, proxyInfo, sendRequest }) => {
        
        // 1. Scrape the main item data
        const mainData = extractMainData();
        const detailUrl = extractDetailUrl();
    
        // 2. Fetch extra details inline without queueing
        if (detailUrl) {  
          // My concern: Does this perfectly mimic the parent request?
          const { body } = await sendRequest({
              url: detailUrl,
              session: session,          // Passing current session
              proxyUrl: proxyInfo?.url,  // Passing current proxy IP
          });
          
          const extraData = extractExtraData(body);
        }
    
        await pushData(mainData);
    });
    Thanks!
    0
    a
    • 2
    • 2
  • Is there a way to enqueue a request without actually making an HTTP request?
    f

    fierDeToiMonGrand

    12/29/2025, 1:12 AM
    What I’m trying to do is leverage Crawlee’s request queue + uniqueKey de-duplication, but I don’t want to hit a real URL. Conceptually, I just want to “switch routes” (change the label) and trigger another operation/state in the crawler, while still using the queue’s uniqueness guarantees. Is this possible, or is a real URL always required when adding a request? Currently getting
    Copy code
    Reclaiming failed request back to the list or queue. Expected `RequestOptions.url` to be of type `string` but received type `undefined`
    I want something like that
    Copy code
    import { v4 as uuidv4 } from 'uuid';
    
    const itemRequests: Partial<Source>[] = dataResults.map((result) => {
        const itemKey = result.item.key; // generic key
        return {
            uniqueKey: request.userData.saveOnlyUniqueItems ? itemKey : uuidv4(),
            label: labels.SPECIFIC_ITEM, // generic label
            userData: {
                ...request.userData,
                itemData: result.item, // pass the data generically
            },
        };
    });
    0
    a
    w
    • 3
    • 5
  • Restart after crash
    a

    Answer Overflow

    12/22/2025, 10:06 AM
    message has been deleted
    0
    m
    w
    • 3
    • 2
  • What is the difference between `output schema` and `dataset schema`
    a

    Answer Overflow

    12/16/2025, 9:44 PM
    message has been deleted
    0
    u
    f
    w
    • 4
    • 9
  • How to aggregate user data from duplicate URLs
    v

    vwkd

    12/02/2025, 1:25 AM
    How can I save the categories of a product with multiple categories? Currently, I'm passing the category in
    userData
    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.
    Copy code
    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
    });
    0
    a
    p
    • 3
    • 2
  • Impit part of Crawlee
    l

    Louis Deconinck

    12/01/2025, 9:37 PM
    Will Impit become a part of Crawlee and replace GotScraping?
    0
    a
    p
    m
    • 4
    • 12
  • AI | Full-Stack Engineer
    a

    ApifyBot

    11/28/2025, 6:00 PM
    @Joy just advanced to level 1! Thanks for your contributions! 🎉
    0
    j
    a
    p
    • 4
    • 3
  • How to use PlaywrightCrawler to listen for ChatGPT's SSE responses on a web page.
    f

    fourier

    11/24/2025, 11:38 AM
    pls. I need help.
    0
    a
    m
    • 3
    • 2
  • Error handling
    m

    Michael

    11/13/2025, 7:57 AM
    Hello error handling behaviour is little unclear for some requests 400 are considered sometime as ok sometime as error even more weird i sometime got empty html (i'm 100% sure that not the produced response)
    Copy code
    <html><head></head><body></body></html>
    ? even after adding
    Copy code
    await waitForSelector('#myID')
    how i suppose to deal with that ? thanks
    0
    o
    • 2
    • 3
  • Retry requests with different headers and etc
    m

    memo23

    11/11/2025, 11:43 PM
    Can we get this page also in JS version: https://crawlee.dev/python/docs/guides/error-handling Also I am interested regarding best practices how to change headers when 403 or 429 are encountered, so I don't repeat same request with same headers and different IP only
    0
    a
    o
    m
    • 4
    • 10
  • Get A Job Offer
    a

    Answer Overflow

    10/27/2025, 4:03 PM
    message has been deleted
    0