Skillshub apify-prod-checklist

install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/jeremylongshore/claude-code-plugins-plus-skills/apify-prod-checklist" ~/.claude/skills/comeonoliver-skillshub-apify-prod-checklist && rm -rf "$T"
manifest: skills/jeremylongshore/claude-code-plugins-plus-skills/apify-prod-checklist/SKILL.md
source content

Apify Production Checklist

Overview

Complete checklist for deploying Actors to the Apify platform and integrating them into production applications. Covers Actor configuration, scheduling, monitoring, alerting, and rollback.

Prerequisites

  • Actor tested locally with
    apify run
  • apify login
    configured with production token
  • Familiarity with
    apify-core-workflow-a
    and
    apify-deploy-integration

Pre-Deployment Checklist

Actor Configuration

  • .actor/actor.json
    has correct
    name
    ,
    title
    ,
    description
  • INPUT_SCHEMA.json
    validates all required inputs
  • Dockerfile
    uses pinned base image version (
    apify/actor-node:20
    , not
    latest
    )
  • package-lock.json
    committed (deterministic installs)
  • Memory set appropriately (start at 1024MB, tune after profiling)
  • Timeout set with buffer (2x expected runtime)

Code Quality

  • Actor.main()
    wraps entry point (handles init/exit/errors)
  • failedRequestHandler
    logs failures without crashing Actor
  • Input validation at Actor start (
    if (!input?.startUrls) throw ...
    )
  • No hardcoded URLs, credentials, or magic numbers
  • Proxy configured for target sites that block datacenter IPs
  • maxRequestsPerCrawl
    set to prevent runaway costs

Data Output

  • Dataset schema documented (consistent field names)
  • SUMMARY
    key-value store record saved with run stats
  • Large payloads chunked (9MB dataset push limit)
  • PII sanitized before storage

Instructions

Step 1: Deploy Actor

# Build and push to Apify platform
apify push

# Verify the build succeeded
apify builds ls

# Test on platform with production-like input
apify actors call username/my-actor \
  --input='{"startUrls":[{"url":"https://target.com"}],"maxItems":10}'

Step 2: Configure Scheduling

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

// Create a scheduled task (cron)
const schedule = await client.schedules().create({
  name: 'daily-product-scrape',
  cronExpression: '0 6 * * *',  // Daily at 6 AM UTC
  isEnabled: true,
  actions: [{
    type: 'RUN_ACTOR',
    actorId: 'username/my-actor',
    runInput: {
      body: JSON.stringify({
        startUrls: [{ url: 'https://target.com/products' }],
        maxItems: 5000,
      }),
      contentType: 'application/json',
    },
    runOptions: {
      memory: 2048,
      timeout: 3600,
      build: 'latest',
    },
  }],
});

console.log(`Schedule created: ${schedule.id}`);

Or configure in Apify Console: Actors > Your Actor > Schedules.

Step 3: Set Up Webhooks for Monitoring

// Create webhook for run completion alerts
const webhook = await client.webhooks().create({
  eventTypes: ['ACTOR.RUN.SUCCEEDED', 'ACTOR.RUN.FAILED', 'ACTOR.RUN.TIMED_OUT'],
  condition: { actorId: 'ACTOR_ID' },
  requestUrl: 'https://your-server.com/api/apify-webhook',
  payloadTemplate: JSON.stringify({
    eventType: '{{eventType}}',
    actorId: '{{actorId}}',
    runId: '{{actorRunId}}',
    status: '{{resource.status}}',
    datasetId: '{{resource.defaultDatasetId}}',
    startedAt: '{{resource.startedAt}}',
    finishedAt: '{{resource.finishedAt}}',
  }),
});

Step 4: Monitor Runs

// Check recent runs for failures
async function checkActorHealth(actorId: string, lookbackHours = 24) {
  const { items: runs } = await client.actor(actorId).runs().list({
    limit: 50,
    desc: true,
  });

  const cutoff = new Date(Date.now() - lookbackHours * 3600_000);
  const recentRuns = runs.filter(r => new Date(r.startedAt) > cutoff);

  const stats = {
    total: recentRuns.length,
    succeeded: recentRuns.filter(r => r.status === 'SUCCEEDED').length,
    failed: recentRuns.filter(r => r.status === 'FAILED').length,
    timedOut: recentRuns.filter(r => r.status === 'TIMED-OUT').length,
    totalCostUsd: recentRuns.reduce((sum, r) => sum + (r.usageTotalUsd ?? 0), 0),
  };

  const successRate = stats.total > 0
    ? ((stats.succeeded / stats.total) * 100).toFixed(1)
    : 'N/A';

  console.log(`Actor: ${actorId}`);
  console.log(`Last ${lookbackHours}h: ${stats.total} runs, ${successRate}% success`);
  console.log(`Failed: ${stats.failed}, Timed out: ${stats.timedOut}`);
  console.log(`Total cost: $${stats.totalCostUsd.toFixed(4)}`);

  if (stats.failed > 0) {
    console.warn('ALERT: Failed runs detected!');
  }

  return stats;
}

Step 5: Implement Rollback

# List available builds
apify builds ls

# Roll back to a previous build
curl -X POST \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  "https://api.apify.com/v2/acts/ACTOR_ID?build=BUILD_NUMBER"

# Or redeploy from a git tag
git checkout v1.2.3
apify push

Step 6: Cost Guard

// Set up a cost guard that aborts runs exceeding budget
async function runWithCostGuard(
  actorId: string,
  input: Record<string, unknown>,
  maxCostUsd: number,
) {
  const run = await client.actor(actorId).start(input);

  // Poll every 30 seconds
  const pollInterval = setInterval(async () => {
    const status = await client.run(run.id).get();
    const cost = status.usageTotalUsd ?? 0;

    if (cost > maxCostUsd) {
      console.error(`Cost guard: $${cost.toFixed(4)} exceeds $${maxCostUsd}. Aborting.`);
      await client.run(run.id).abort();
      clearInterval(pollInterval);
    }
  }, 30_000);

  const finished = await client.run(run.id).waitForFinish();
  clearInterval(pollInterval);
  return finished;
}

Production Alert Conditions

AlertConditionSeverity
Run failed
status === 'FAILED'
P1
Run timed out
status === 'TIMED-OUT'
P2
Low yieldDataset items < expected thresholdP2
High cost
usageTotalUsd > budget
P2
Consecutive failures3+ failures in a rowP1
No runs in windowSchedule didn't triggerP1

Error Handling

IssueCauseSolution
Build fails on platformLocal deps differCommit
package-lock.json
Schedule not firingCron syntax errorValidate at crontab.guru
Webhook not receivedURL not reachableUse ngrok for testing; check HTTPS
Memory exceededWorkload too largeIncrease memory or reduce concurrency
Unexpected cost spikeNo
maxRequestsPerCrawl
Always set an upper bound

Resources

Next Steps

For version upgrades, see

apify-upgrade-migration
.