executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
apify-cost-tuningOptimize Apify platform costs through memory tuning, compute unit management, and proxy budgeting. Use when analyzing Apify billing, reducing Actor run costs, or implementing usage monitoring and budget alerts. Trigger with "apify cost", "apify billing", "reduce apify costs", "apify pricing", "apify expensive", "apify budget", "compute units".
Independent GitHub snapshot · Automated classification · Original documentation governs
name: apify-cost-tuning description: 'Optimize Apify platform costs through memory tuning, compute unit management, and proxy budgeting. Use when analyzing Apify billing, reducing Actor run costs, or implementing usage monitoring and budget alerts. Trigger with "apify cost", "apify billing", "reduce apify costs", "apify pricing", "apify expensive", "apify budget", "compute units".' allowed-tools: Read, Grep version: 1.5.0 license: MIT author: Jeremy Longshore jeremy@intentsolutions.io tags:
Apify charges on three axes: compute units (CU), proxy traffic (GB), and storage. One CU = 1 GB of memory running for 1 hour, so cost scales with both memory allocation and run duration. This skill walks the investigate → tune → guard loop that finds where spend is going, cuts it at the biggest lever (memory), and installs guardrails so it stays down.
Full pricing tables (plan CU prices, proxy rates, storage rules) live in pricing-model.md.
APIFY_TOKEN set in the environment.apify-client package installed (npm install apify-client).The workflow is six steps. Each is summarized here with its core lever; the full, runnable code for every step is in implementation.md.
Analyze current costs — roll up the last N days of runs into total CU, USD, and duration, and surface the single most expensive run:
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const { items: runs } = await client.actor(actorId).runs().list({ limit: 1000, desc: true });
const totalUsd = runs.reduce((s, r) => s + (r.usageTotalUsd ?? 0), 0);
Reduce memory allocation (biggest lever) — sweep memory from 4096 MB down to 256 MB and stop at the first failure to find the sweet spot. Most CheerioCrawler Actors are over-provisioned. Sweet spots: simple Cheerio 256-512 MB, complex 512-1024 MB, Playwright 2048-4096 MB.
Optimize crawl duration — higher maxConcurrency, tighter
requestHandlerTimeoutSecs, a maxRequestsPerCrawl cap, fewer retries, and
selective enqueueLinks. Faster crawls consume fewer CUs.
Minimize proxy costs — prefer datacenter (free with plan), only reach for
residential when a site blocks it, block images/fonts/CSS to save residential GB,
and reuse proxy sessions with useSessionPool.
Cost guard for runaway Actors — start the run, poll usageTotalUsd every 30s,
and .abort() once spend crosses a hard cap.
Monitor monthly usage — iterate every Actor's runs since the 1st of the month and print a cost-descending report so the top spenders are obvious.
See full walkthrough for the complete code of each step, including the memory sweep, proxy hooks, budget guard, and monthly report.
Running this skill produces:
maxRequestsPerCrawl set to prevent runaway crawlsmaxConcurrency tuned (higher = faster = fewer CUs)| Issue | Cause | Solution |
|---|---|---|
| Unexpected cost spike | No maxRequestsPerCrawl | Always set an upper bound |
| High residential proxy cost | Scraping images/fonts | Block non-essential resources |
| Over-provisioned memory | Default 1024MB | Profile and reduce to minimum |
| Too many scheduled runs | Aggressive cron | Reduce frequency if data freshness allows |
Three worked scenarios chain the steps against concrete symptoms — a CheerioCrawler bill that tripled, runaway residential-proxy GB, and guarding a brand-new Actor. Each shows the full investigate → tune → verify loop. See examples.md.
Quick guard example — abort any run that exceeds $0.50:
// runWithBudget polls usageTotalUsd every 30s and aborts past the cap
const run = await runWithBudget('user/scraper', input, 0.50);
For architecture patterns, see apify-reference-architecture.