Apify webhooks events
'Implement Apify webhooks for Actor run notifications and event-driven pipelines.From its SKILL.md
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill apify-webhooks-eventsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
6.1 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
Apify Webhooks & Events
Overview
Configure webhooks to receive notifications when Actor runs complete, fail, or time out. Apify supports both persistent webhooks (for all runs of an Actor) and ad-hoc webhooks (for a single run). Event-driven architecture is the recommended pattern for production Apify integrations.
Prerequisites
npm install apify-clientin your project (andexpressif you build an HTTP handler)- An API token in
APIFY_TOKEN— read it from the environment (process.env.APIFY_TOKEN) or passAuthorization: Bearer $APIFY_TOKENon REST calls, never hard-code it - A public HTTPS endpoint for Apify to POST to (use ngrok while developing)
- Familiarity with
apify-sdk-patterns
Event Types
| Event | Fired When |
|---|---|
ACTOR.RUN.CREATED | A new Actor run starts |
ACTOR.RUN.SUCCEEDED | Run finishes with SUCCEEDED status |
ACTOR.RUN.FAILED | Run finishes with FAILED status |
ACTOR.RUN.ABORTED | Run is manually or programmatically aborted |
ACTOR.RUN.TIMED_OUT | Run exceeds its timeout |
ACTOR.RUN.RESURRECTED | A finished run is resurrected |
Instructions
Step 1: Create a Persistent Webhook
Persistent webhooks fire for every run of an Actor. Set condition.actorId, list
the eventTypes you care about, and shape the delivered body with
payloadTemplate:
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const webhook = await client.webhooks().create({
eventTypes: ['ACTOR.RUN.SUCCEEDED', 'ACTOR.RUN.FAILED', 'ACTOR.RUN.TIMED_OUT'],
condition: { actorId: 'YOUR_ACTOR_ID' },
requestUrl: 'https://your-app.com/api/webhooks/apify',
payloadTemplate: JSON.stringify({
eventType: '{{eventType}}',
actorRunId: '{{actorRunId}}',
defaultDatasetId: '{{resource.defaultDatasetId}}',
status: '{{resource.status}}',
statusMessage: '{{resource.statusMessage}}',
}),
isAdHoc: false,
});
console.log(`Webhook created: ${webhook.id}`);
The full payload template (all run fields) and the complete variable table are in payload templates & local testing.
Step 2: Use Ad-Hoc Webhooks for Single Runs
Ad-hoc webhooks are created at run time and fire only for that specific run — pass
a webhooks array when starting the Actor:
const run = await client.actor('username/my-actor').start(
{ startUrls: [{ url: 'https://example.com' }] },
{
webhooks: [{
eventTypes: ['ACTOR.RUN.SUCCEEDED', 'ACTOR.RUN.FAILED'],
requestUrl: 'https://your-app.com/api/webhooks/apify',
}],
},
);
The equivalent REST/curl form is in payload templates & local testing.
Step 3: Handle the Webhook
Your endpoint must return a 2xx within 30 seconds, so acknowledge immediately and
process asynchronously. On SUCCEEDED, fetch the dataset via defaultDatasetId; on
FAILED/TIMED_OUT, pull the run log and alert:
app.post('/api/webhooks/apify', async (req, res) => {
res.status(200).json({ received: true }); // ack first
try {
await processWebhook(req.body); // switch on eventType, fetch dataset, alert
} catch (error) {
console.error('Webhook processing failed:', error);
}
});
The full processWebhook switch (dataset fetch, log tail, oncall alerting) is in
full implementation.
Step 4: Make Processing Idempotent, Chain Pipelines, and Manage Webhooks
Apify may deliver a webhook more than once, so dedupe on
${actorRunId}:${eventType} before doing work. You can also chain Actors (Stage 1
SUCCEEDED → start Stage 2) and manage the webhook lifecycle (list, update,
delete, inspect dispatches). All three patterns — idempotent processing,
event-driven pipeline, and lifecycle management — are in
full implementation.
Output
- A created webhook returns its
id(persistent webhooks are visible underclient.webhooks().list(); ad-hoc webhooks are scoped to one run) - On each matching event, Apify POSTs the rendered
payloadTemplateJSON to yourrequestUrl client.webhook(id).dispatches().list()returns the delivery history — each entry carries astatus,createdAt, and the endpoint'sresponseStatusso you can confirm delivery or diagnose retries
Examples
- Persistent + ad-hoc webhook creation — Steps 1 and 2 above
- Full handler, idempotency, pipeline chaining, lifecycle management — full implementation
- Payload template variables, REST/
curlcreation, and local testing with ngrok — payload templates & local testing
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Webhook not delivered | URL unreachable | Verify HTTPS, check firewall |
| Duplicate processing | Webhook retry on non-2xx | Implement idempotency |
| Slow processing | Handler takes >30s | Respond 200 immediately, process async |
| Missing data in payload | Wrong template vars | Check template variable spelling |
| Webhook disabled | Too many failures | Re-enable in Console or via API |
Resources
Next Steps
For performance optimization, see apify-performance-tuning.
What ships with it: 2 files
6.0 KB alongside SKILL.md
references/
- examples.md1.6 KB
- implementation.md4.4 KB