{
  "name": "Detect Apify actor output drift with Datasource Pulse and email alerts",
  "nodes": [
    {
      "parameters": {
        "content": "## Detect Apify actor output drift with Datasource Pulse and email alerts\n\n**Who's it for**\nAnyone depending on an Apify actor's output quality: your own actors, or public actors you build on.\n\n**How it works**\nScrapers rarely die loudly; they keep succeeding while returning fewer items, stale data, or higher costs. Daily, Datasource Pulse baselines the watched actor's recent runs and alerts on volume drops, cost spikes, and staleness, with the thresholds you set.\n\n**How to set up (5 min)**\n1. Install the **Apify** community node (n8n Cloud: search \"Apify\" in the nodes panel and install) and connect your Apify account.\n2. Open **Initiate Datasource Pulse** and edit *Input JSON*:\n   - `actorId`: the actor to watch (yours, or any public actor you depend on)\n   - `apifyToken`: token with Actor read + run-read scope\n   - Tune `volumeDropPct` (default 30), `costSpikePct` (default 50), `stalenessThresholdDays`\n3. Configure SMTP in **Send Email Alert** (or swap in Gmail/Slack).\n4. Run once and confirm the alert fires. The IF node ships preset to pass anything whose state is not healthy.\n\n**Requirements**\nApify account ($0.02 per check per run), the Apify community node (verified on n8n Cloud; self-hosted installs @apify/n8n-nodes-apify), SMTP credentials.\n\n**How to customize**\nBaselines assume similar inputs per run: set the baseline flags to false for actors run with varying queries, staleness and cost checks still apply. Swap the email node for Gmail or Slack. Cost: 1 actor at 1 run/day is about $0.61/month.\n\nDocs: https://datasourcepulse.com/integrations/n8n",
        "height": 1140,
        "width": 520
      },
      "id": "sticky-setup",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -700,
        -420
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "daysInterval": 1,
              "triggerAtHour": 7,
              "triggerAtMinute": 30
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "When Every Day at 7:30",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -80,
        40
      ]
    },
    {
      "parameters": {
        "resource": "Actors",
        "operation": "Run actor and get dataset",
        "actorId": {
          "__rl": true,
          "value": "UEt39k7v1DkIYp8Gh",
          "mode": "list",
          "cachedResultName": "Datasource Pulse (growth_wizard/datasource-pulse)",
          "cachedResultUrl": "https://console.apify.com/actors/UEt39k7v1DkIYp8Gh/input"
        },
        "customBody": "{\n  \"checks\": [\n    {\n      \"type\": \"actor\",\n      \"id\": \"watched-actor\",\n      \"label\": \"Watched actor · output drift\",\n      \"actorId\": \"username~actor-to-watch\",\n      \"apifyToken\": \"PASTE_APIFY_TOKEN_WITH_ACTOR_READ_AND_RUN_READ_SCOPE\",\n      \"enableVolumeBaseline\": true,\n      \"enableCostBaseline\": true,\n      \"stalenessThresholdDays\": 7,\n      \"volumeDropPct\": 30,\n      \"costSpikePct\": 50,\n      \"impact\": \"Downstream data consumers get thin or stale data when this drifts\"\n    }\n  ]\n}",
        "actorSource": "recentlyUsed"
      },
      "id": "run-datasource-pulse",
      "name": "Initiate Datasource Pulse",
      "type": "@apify/n8n-nodes-apify.apify",
      "typeVersion": 1,
      "position": [
        160,
        40
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "state-not-healthy",
              "leftValue": "={{ $json.state }}",
              "rightValue": "healthy",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-unhealthy",
      "name": "If State Unhealthy",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        400,
        40
      ]
    },
    {
      "parameters": {
        "fromEmail": "alerts@yourdomain.com",
        "toEmail": "you@example.com",
        "subject": "=🚨 {{ $json.connector_label }} · {{ $json.state }} (Datasource Pulse)",
        "emailFormat": "text",
        "text": "={{ $json.message }}\n\nConnector: {{ $json.connector_id }}\nState: {{ $json.state }}\nFailure class: {{ $json.failure_class }}\nChecked at: {{ $json.run_at }}",
        "options": {}
      },
      "id": "email-alert",
      "name": "Send Email Alert",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        640,
        20
      ]
    },
    {
      "parameters": {
        "content": "### 1 · Schedule\nTune the cadence here. Cost scales with runs per day.",
        "height": 150,
        "width": 220,
        "color": 7
      },
      "id": "sticky-step-1",
      "name": "Sticky Note (sticky-step-1)",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -110,
        -140
      ]
    },
    {
      "parameters": {
        "content": "### 2 · Run the checks\nDatasource Pulse runs every check in *Input JSON* and returns one verdict per check, each with a stable failure_class.",
        "height": 190,
        "width": 230,
        "color": 7
      },
      "id": "sticky-step-2",
      "name": "Sticky Note (sticky-step-2)",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        130,
        -180
      ]
    },
    {
      "parameters": {
        "content": "### 3 · Alert on anything not healthy\nhealthy verdicts stop at the filter; volume drops, cost spikes, and staleness go out by email.",
        "height": 150,
        "width": 430,
        "color": 7
      },
      "id": "sticky-step-3",
      "name": "Sticky Note (sticky-step-3)",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        380,
        -140
      ]
    }
  ],
  "connections": {
    "When Every Day at 7:30": {
      "main": [
        [
          {
            "node": "Initiate Datasource Pulse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Initiate Datasource Pulse": {
      "main": [
        [
          {
            "node": "If State Unhealthy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If State Unhealthy": {
      "main": [
        [
          {
            "node": "Send Email Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}
