The Apify JavaScript SDK, and when a Store Actor is the cheaper answer
The Apify SDK for JavaScript is the apify npm package (3.7.2, Apache-2.0, npmjs.com/package/apify, checked 2026-09-09). It does not crawl. Crawling moved to Crawlee in SDK v3; apify keeps the platform half — Actor lifecycle, datasets, key-value store, input, proxy configuration, and pay-per-event charging. Install with npm install apify crawlee, run locally with apify run, deploy with apify push.
Most developers arrive at the Apify SDK sideways. You find a Store Actor that does 80% of the job, hit the one field it will not return, and decide to write your own. Sometimes that is the right call. More often nobody runs the arithmetic first, and the custom Actor costs more in maintenance than the Store Actor ever charged in fees.
That split is Apify's own framing: "Crawlee, the new web-scraping library" and "helpers for the Apify platform, available as apify package on NPM" (checked 2026-09-09). It matters for the decision below, because the crawling half runs anywhere and the platform half only pays for itself if you use the platform.
Should you write your own Actor, or run one from the Store?
Apify Store advertises "70,000+ ready-to-run tools called Actors" (apify.com/store, checked 2026-09-09). The public listing API (api.apify.com/v2/store, checked 2026-09-09) returns roughly 57,000 on the same day, and that total moves by hundreds between calls, so treat the marketing figure as the ceiling and the API figure as a rough count of what you can actually browse. Either way, check before you build.
| Question | Store Actor | Your own SDK Actor |
|---|---|---|
| What you pay | Author's per-result or per-event price, on top of platform costs | Compute and proxy only, at your plan's rate |
| Fields you get | Whatever the author exposes in the output | Whatever you write |
| Who fixes it when the target site changes | The author | You |
| Repricing risk | Author can change the model with notice | Only Apify's own plan pricing |
| Disappearance risk | Actor can be deprecated or removed outright | Yours until you delete it |
| Time to first row | Minutes | Hours to days |
If you need a field the Actor does not return, or you need the crawl logic itself to be different, write your own. If you only need more rows of what it already returns, you are about to pay yourself to rebuild something that costs $0.004 a row.
What does a Store Actor actually cost per row?
Take the Google Maps scraper, the most-used Actor in the Store, with more than 596,000 users (api.apify.com/v2/acts/compass~crawler-google-places, stats.totalUsers 596,308, checked 2026-09-09). It is pay-per-event. The primary event, "Scraped place", is priced at $0.004 per place on the free tier and drops to $0.003 and lower on paid tiers, plus a $0.00005 Actor Start charge per GB of memory (api.apify.com/v2/acts/compass~crawler-google-places, checked 2026-09-09).
Ten thousand places therefore cost $40 on the free tier, $30 one tier up.
Now price the alternative. A compute unit is memory times duration — "1024MB memory x 1 hour = 1 CU" (docs.apify.com/platform/actors/running/usage-and-resources, checked 2026-09-09) — and a CU costs $0.20/CU subject to change · verified 2026-09-09 on the Free and Starter plans, $0.16 on Scale and $0.13 on Business (apify.com/pricing, checked 2026-09-09). A PlaywrightCrawler at 4 GB burns 4 CU an hour, so $0.80 an hour.
So $30 of Store Actor fees buys you roughly 37 hours of your own 4 GB browser crawler. That is the whole break-even, and it moves the moment you need residential proxies: those bill separately at $8/GB on Free and Starter, down to $7/GB on Business (same source, same date).
We have not benchmarked a hand-written Maps crawler and will not quote a pages-per-hour figure we did not measure. The shape of the arithmetic is the point. Run your own crawler against 500 targets, read the actual CU spend in the Console, and multiply.
One planning caveat while you size that run: Apify's own two sources disagree on Free-plan concurrency. apify.com/pricing lists 5 concurrent runs on Free; docs.apify.com/platform/limits lists 25 (both checked 2026-09-09). They agree on every paid tier: 32 on Starter, 128 on Scale, 256 on Business. Assume 5 when you plan a parallel schedule, and confirm on your account's Limits page before you depend on it. The Apify free plan breakdown covers what $5 of monthly credit actually buys.
What goes wrong when you depend on a Store Actor?
Two failure modes, both verifiable from the API today, and neither of them is in the vendor's tutorial.
An Actor can be removed and silently replaced. api.apify.com/v2/acts/apify~google-maps-scraper returns 404 record-not-found as of 2026-09-09. The web URL does not 404: apify.com/apify/google-maps-scraper returns a 308 to apify.com/compass/crawler-google-places, a different Actor by a different author with different input and different pricing. A link checker that only looks at HTTP status sees a healthy 200 and tells you nothing.
Rental pricing can be converted under you. trudax/reddit-scraper is flagged isDeprecated: true and still charges a $45/month flat rental. Its pricing record shows a PAY_PER_EVENT model starting 2026-09-21, with users notified on 2026-09-07 (api.apify.com/v2/acts/trudax~reddit-scraper, checked 2026-09-09). Fourteen days of notice, and every cost model built on that $45 line is void. The maintained replacement, trudax/reddit-scraper-lite, is already pay-per-event at $0.004 per stored result plus $0.02 per GB at Actor start.
Neither risk is a reason to avoid the Store. They are a reason to check isDeprecated and pricingInfos on the API before you write a Store Actor into a budget or a scheduled pipeline. If an Actor is the backbone of a production system, that check belongs in an Actor health probe on a schedule, not in your memory.
Which Node.js version do Apify Actors run?
This is where most JavaScript SDK tutorials, including the earlier version of this page, are actively wrong. Three different floors apply, and only the highest one matters.
| Layer | Declared requirement | Source, checked 2026-09-09 |
|---|---|---|
apify 3.7.2 | node >=16.0.0 | npm registry, package engines |
crawlee 3.18.1 | node >=16.0.0 | npm registry, package engines |
apify-cli 1.10.0 | node >=20 | npm registry, package engines |
| Apify base images | Node.js 20, 22, 24 | docs.apify.com/sdk/js docker images |
The binding constraint is the CLI and the base image, not the libraries. And one of the three image versions is already past end of life: Node 20 ended 2026-04-30, while Node 22 runs to 2027-04-30 and Node 24 to 2028-04-30 (nodejs.org release schedule, checked 2026-09-09). Node 18, which older Apify tutorials still name, ended 2025-04-30 and is no longer a current image tag.
Use Node 24 for a new Actor. Pin it in the image tag, because Apify's own guidance is to "always using at least the Node.js version tag in production Dockerfiles" so a future Node update cannot break the build:
FROM apify/actor-node:24
Pin the same major in package.json under engines if more than one person touches the repo. Node 22 is a defensible second choice if a dependency you need has not caught up; Node 20 and Node 18 are not choices at all any more.
How do you build and deploy the Actor?
- Install the CLI.
npm install -g apify-cli. Check it withapify --version. The CLI needs Node 20 or later, so do this after the version decision above, not before. - Scaffold.
apify create my-js-scraper. The CLI prompts for a template;apify templates ls"prints all available Actor templates, including the use cases and language each one supports" (docs.apify.com/cli/docs/reference, checked 2026-09-09). The JavaScript entries include JavaScript one-page scraper, JavaScript Cheerio crawler, JavaScript Playwright scraper, Empty JavaScript Actor and JavaScript API Actor (apify/actor-templates manifest, checked 2026-09-09). Skip the prompt withapify create my-js-scraper -t js-crawlee-playwright-chrome. - Write the Actor. The four calls below carry the whole platform contract.
import { Actor } from "apify";
import { PlaywrightCrawler } from "crawlee";
await Actor.init();
const { startUrls = ["https://crawlee.dev"], maxPages = 50 } = (await Actor.getInput()) ?? {};
const crawler = new PlaywrightCrawler({
maxRequestsPerCrawl: maxPages,
proxyConfiguration: await Actor.createProxyConfiguration(),
async requestHandler({ request, page, enqueueLinks, log }) {
const title = await page.title();
log.info(`${request.loadedUrl} -> ${title}`);
await Actor.pushData({ title, url: request.loadedUrl });
await enqueueLinks();
},
});
await crawler.run(startUrls);
await Actor.exit();
- Run it locally.
apify login, thenapify run. The CLI "executes Actor locally with simulated Apify environment variables" and "stores data in localstoragedirectory", so your rows land in./storage/datasets/defaultbefore anything reaches the cloud (CLI reference, checked 2026-09-09). - Deploy.
apify push"deploys Actor to Apify platform using settings from.actor/actor.json". Open the Console, start the run, and read results under Storage then Datasets.
Cap maxRequestsPerCrawl while you are learning. An unbounded enqueueLinks() on a large site is the fastest way to spend a month of credits in an afternoon.
What does the SDK give you that Crawlee alone does not?
Crawlee gives you CheerioCrawler for plain HTTP, PlaywrightCrawler for a real browser, and PuppeteerCrawler (crawlee.dev, checked 2026-09-09). Everything below is the apify package, and every one of these is dead weight if you are not running on Apify.
| SDK call | What it does |
|---|---|
Actor.init() | Initializes the Actor, switching to platform storage when it detects it is running on Apify |
Actor.getInput() | Reads the run's input object from the default key-value store |
Actor.pushData() | Appends objects to the run's default dataset |
Actor.openKeyValueStore() | Named stores for screenshots, HTML snapshots, and other blobs |
Actor.createProxyConfiguration() | Wires Apify Proxy into a Crawlee crawler |
Actor.charge() | "Charge for a specified number of events" — the pay-per-event hook if you publish |
Actor.exit() | Ends the run with a status message and exit code |
Method names and descriptions from the Apify SDK Actor class reference, checked 2026-09-09. Actor.charge() is the one worth knowing early: if you ever publish, it is how your Actor bills, and monetizing an Actor is a different design problem from building one.
When you should not use Apify at all
Crawlee is Apache-2.0 and does not require an Apify account (npmjs.com/package/crawlee, checked 2026-09-09). If you already run schedulers, containers, proxies and object storage, and you only wanted a crawling library, take Crawlee and skip the platform. You will pay nothing per CU and nothing per result, and you will keep every operational burden the platform was absorbing: retries, run history, dataset exports, concurrency limits, proxy rotation, and someone else's uptime.
If you are not already running that infrastructure for another reason, the platform is cheaper than reproducing it. If you are, the apify package is the only part you can drop, and it is the smaller half of what the platform was doing for you.
What changed on this page, 2026-09-09
The previous version told readers to use "Node.js 18+" and answered a FAQ with "the current Node LTS (18 or 20+)". Node 18 has been end of life since 2025-04-30 and Node 20 since 2026-04-30, so that advice recommended two dead runtimes while claiming to avoid them. It now says Node 24, with the three conflicting version floors laid out. The page was also rebuilt around the build-or-rent decision, because the step-by-step quickstart it used to contain is already on docs.apify.com and was not worth a second copy.
Where to go next
- Scraping dynamic websites with Playwright: logins, infinite scroll, and the pages that fight back.
- Processing scraped data: getting rows out of a dataset and into somewhere useful.
- Apify API tutorial: triggering runs and reading datasets without the SDK at all.
- Turn an Actor into a real-time API: standby mode, for when a scheduled run is too slow.
Ready to run the arithmetic on your own target? Start on the Apify free plan and measure one crawl before you commit to building anything. The $5 of monthly credit is enough to price the comparison, and you will know within an hour whether the Store Actor was already cheaper.
Crawlee is the open-source crawling library: request queues, HTTP, Cheerio, Playwright, sessions and routing. The Apify SDK is the apify npm package and covers platform integration only: Actor lifecycle, dataset and key-value storage, input, proxy configuration and pay-per-event charging. Apify split them in SDK v3. Actors normally import both; a scraper running on your own servers needs only Crawlee.
Node 24. Apify base images ship Node 20, 22 and 24, and the Apify CLI 1.10.0 declares engines node >=20, so the practical floor is 20 even though the apify and crawlee packages declare >=16. Node 18 reached end of life on 2025-04-30 and Node 20 on 2026-04-30, so neither is a safe default. Pin the major in the image tag, for example FROM apify/actor-node:24.
Compare the Actor's per-result price against your compute bill. The Google Maps Actor charges $0.004 per place on the free tier, so 10,000 places is $40. A 4 GB PlaywrightCrawler costs 4 compute units an hour, and a CU is $0.20 on Free and Starter, so $0.80 an hour. Building wins only if your crawler finishes well inside that budget and does not need residential proxies at $8 per GB.
Query api.apify.com/v2/acts/USER~NAME and read isDeprecated, modifiedAt and pricingInfos. A deprecated Actor can still run and still bill. A pricingInfos entry with a future startedAt is a scheduled repricing. HTTP status checks are not enough: apify.com/apify/google-maps-scraper returns a 308 to a completely different Actor, so a link checker sees 200 while the Actor you named is gone.
Run apify login, then apify push from the project root. The CLI deploys the Actor using settings from .actor/actor.json. You can also connect a GitHub repository for automatic builds. The Console then lets you run, schedule and monitor the Actor.
Dataset items are written under storage/datasets/default as JSON files. The CLI simulates the Apify environment variables, so local behaviour mirrors the cloud closely enough to debug against.
Yes. Pick a TypeScript template with apify create, or add types yourself; both the apify and crawlee packages ship their own type definitions for request handlers, datasets and inputs.
Yes, Apify publishes a Python SDK alongside the JavaScript one, and Crawlee has a Python port. The build-or-rent arithmetic on this page is identical in either language, because it is driven by Actor pricing and compute units rather than by the SDK.