{
  "name": "Shopify advertiser leads — weekly new stores to Google Sheets",
  "nodes": [
    {
      "id": "8de62c44-8ef2-5a1e-9244-9962760858e2",
      "name": "Run manually",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "parameters": {}
    },
    {
      "id": "14393dd2-50b5-5acf-9593-bdd1a5f332b2",
      "name": "Weekly Monday",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        180
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "weeksInterval": 1,
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 9,
              "triggerAtMinute": 0
            }
          ]
        }
      }
    },
    {
      "id": "c424694c-dda8-5bf2-aeea-c0068b836744",
      "name": "Configure search",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        240,
        0
      ],
      "parameters": {
        "jsCode": "return [{json:{searchQueries:['skincare'],country:'US',maxAds:150,maxStoresToCheck:40,maxResults:25,requireEmail:true,historyMode:'ONLY_NEW',historyKey:'my-weekly-shopify-advertisers'}}];"
      }
    },
    {
      "id": "a5b1ff19-9dba-52e1-a23d-be280a7b795c",
      "name": "Start Actor",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        480,
        0
      ],
      "parameters": {
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "method": "POST",
        "url": "https://api.apify.com/v2/acts/apivault_labs~shopify-advertiser-leads-finder/runs",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "build",
              "value": "latest"
            },
            {
              "name": "memory",
              "value": "256"
            },
            {
              "name": "timeout",
              "value": "900"
            },
            {
              "name": "maxTotalChargeUsd",
              "value": "0.50"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json) }}",
        "options": {
          "timeout": 60000
        }
      }
    },
    {
      "id": "1bb82a99-615a-5369-8453-f1180ae45552",
      "name": "Wait for Actor",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        720,
        0
      ],
      "parameters": {
        "resume": "timeInterval",
        "amount": 20,
        "unit": "seconds"
      }
    },
    {
      "id": "df8880a0-baea-5be1-9693-4219b4454a21",
      "name": "Get run status",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        960,
        0
      ],
      "parameters": {
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "url": "={{ 'https://api.apify.com/v2/actor-runs/' + $('Start Actor').first().json.data.id }}",
        "options": {
          "timeout": 60000
        }
      }
    },
    {
      "id": "e6d06f86-9349-5e9e-8ff2-97f6d5f16f14",
      "name": "Validate run",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1200,
        0
      ],
      "parameters": {
        "jsCode": "const run=$input.first().json.data;\nif (!run?.id || !run?.status || !run?.startedAt) throw new Error('Missing Apify run response');\nif (['FAILED','ABORTED','TIMED-OUT'].includes(run.status)) throw new Error(`Apify run ${run.id}: ${run.status}. Inspect its log; do not automatically create another run.`);\nif (run.status!=='SUCCEEDED' && Date.now()-Date.parse(run.startedAt)>20*60*1000) throw new Error(`Polling deadline reached for ${run.id}. Inspect this run before restarting.`);\nreturn [{json:{...run,ready:run.status==='SUCCEEDED'}}];"
      }
    },
    {
      "id": "7fbaaed3-a491-5e8e-aabe-3e997928b9ea",
      "name": "Run succeeded",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1440,
        0
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "ready",
              "leftValue": "={{ $json.ready }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      }
    },
    {
      "id": "8fe09813-05be-5435-8cd2-582339ecfb2b",
      "name": "Fetch results",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1680,
        0
      ],
      "parameters": {
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "url": "={{ 'https://api.apify.com/v2/datasets/' + $json.defaultDatasetId + '/items' }}",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "clean",
              "value": "true"
            },
            {
              "name": "limit",
              "value": "1000"
            }
          ]
        },
        "options": {
          "timeout": 60000
        }
      }
    },
    {
      "id": "8230a2f9-2158-574d-a84b-5256d6b539f2",
      "name": "Prepare sheet rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1920,
        0
      ],
      "parameters": {
        "jsCode": "const result=[];\nfor (const item of $input.all()) {\n const r=item.json;\n if (!r.domain) continue;\n result.push({json:{domain:r.domain,storeName:r.storeName||'',website:r.website||'',primaryEmail:r.primaryEmail||'',primaryEmailRelation:r.primaryEmailRelation||'',primaryEmailSource:r.primaryEmailSource||'',primaryPhone:r.primaryPhone||'',activeAdsObserved:r.activeAdsObserved||0,videoAdsObserved:r.videoAdsObserved||0,technologyNames:(r.technologyNames||[]).join(', '),sampleAdUrl:r.sampleAdUrl||'',evidenceScore:r.evidenceScore||0,whyThisLead:r.whyThisLead||'',historyStatus:r.historyStatus||'',checkedAt:r.checkedAt||''}});\n}\nreturn result;"
      }
    },
    {
      "id": "94b10082-2a16-57a3-a96f-592a57ce7ca8",
      "name": "Upsert by domain",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.6,
      "position": [
        2160,
        0
      ],
      "parameters": {
        "resource": "sheet",
        "operation": "appendOrUpdate",
        "documentId": {
          "__rl": true,
          "value": "REPLACE_WITH_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Leads",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {},
          "matchingColumns": [
            "domain"
          ],
          "schema": [
            {
              "id": "domain",
              "displayName": "domain",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "storeName",
              "displayName": "storeName",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "website",
              "displayName": "website",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "primaryEmail",
              "displayName": "primaryEmail",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "primaryEmailRelation",
              "displayName": "primaryEmailRelation",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "primaryEmailSource",
              "displayName": "primaryEmailSource",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "primaryPhone",
              "displayName": "primaryPhone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "activeAdsObserved",
              "displayName": "activeAdsObserved",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "videoAdsObserved",
              "displayName": "videoAdsObserved",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "technologyNames",
              "displayName": "technologyNames",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "sampleAdUrl",
              "displayName": "sampleAdUrl",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "evidenceScore",
              "displayName": "evidenceScore",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "whyThisLead",
              "displayName": "whyThisLead",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "historyStatus",
              "displayName": "historyStatus",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "checkedAt",
              "displayName": "checkedAt",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ]
        },
        "options": {
          "cellFormat": "RAW",
          "handlingExtraData": "error"
        }
      }
    },
    {
      "id": "f76bb735-9a26-5867-a139-1b99413eefb8",
      "name": "Setup and recovery",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        100,
        -350
      ],
      "parameters": {
        "content": "## Connect before activation\nSelect an HTTP Header Auth credential on all 3 HTTP nodes: Authorization = Bearer YOUR_APIFY_TOKEN. Connect your Google Sheets OAuth credential, replace spreadsheet ID, create a Leads sheet and paste the documented headers. Weekly schedule: Monday09:00 in workflow timezone. Workflow is inactive.\n\n## Delivery recovery\nONLY_NEW remembers Actor delivery, not successful Sheet writes. If Sheets fails, retry Fetch results from the SAME run/dataset; do not rerun Start Actor. Upsert by domain prevents duplicate rows during replay. Do not overlap executions with the same historyKey. Start Actor intentionally has no auto-retry. The $0.50 run cap leaves room for result events and caller-paid resources; it does not guarantee25 rows.",
        "height": 300,
        "width": 840
      }
    }
  ],
  "connections": {
    "Run manually": {
      "main": [
        [
          {
            "node": "Configure search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly Monday": {
      "main": [
        [
          {
            "node": "Configure search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configure search": {
      "main": [
        [
          {
            "node": "Start Actor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Actor": {
      "main": [
        [
          {
            "node": "Wait for Actor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Actor": {
      "main": [
        [
          {
            "node": "Get run status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get run status": {
      "main": [
        [
          {
            "node": "Validate run",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate run": {
      "main": [
        [
          {
            "node": "Run succeeded",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run succeeded": {
      "main": [
        [
          {
            "node": "Fetch results",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait for Actor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch results": {
      "main": [
        [
          {
            "node": "Prepare sheet rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare sheet rows": {
      "main": [
        [
          {
            "node": "Upsert by domain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "timezone": "Europe/Minsk",
    "executionTimeout": 1500
  },
  "pinData": {},
  "tags": []
}
