AutomationFlowsMarketing & Ads › Extract Leads From an Apollo Search URL Into Google Sheets

Extract Leads From an Apollo Search URL Into Google Sheets

BySalman Mehboob @salmanmehboob on n8n.io

Stop manually downloading CSVs or risking account bans with sketchy UI scrapers! This workflow bridges the gap between Apollo.io's powerful search filters and your Google Sheets database using Apollo's official REST API.

Event trigger★★★★☆ complexity15 nodesGoogle SheetsHTTP Request
Marketing & Ads Trigger: Event Nodes: 15 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #15176 — we link there as the canonical source.

This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "873f84ec-88d8-4f78-a426-25ee26398026",
      "name": "When clicking \u2018Execute workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1712,
        832
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "ee2db9cb-7b85-4306-b969-87a31e567aa1",
      "name": "Extract People",
      "type": "n8n-nodes-base.code",
      "position": [
        -704,
        384
      ],
      "parameters": {
        "jsCode": "// Extract people array from Apollo API response\nconst contacts = $input.first().json.people;\nreturn contacts.map(contact => ({ json: contact }));"
      },
      "typeVersion": 2
    },
    {
      "id": "20b4c29d-032f-4381-96da-8abf255d3536",
      "name": "Write to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -480,
        384
      ],
      "parameters": {
        "columns": {
          "value": {
            "Title": "={{ $json.title }}",
            "Website": "={{ $json.organization.website_url }}",
            "Apollo id": "={{ $json.id }}",
            "Full Name": "={{ $json.name }}",
            "Last Name": "={{ $json.last_name }}",
            "First Name": "={{ $json.first_name }}",
            "Org Twitter": "={{ $json.organization.twitter_url }}",
            "Contact City": "={{ $json.city }}",
            "Founded year": "={{ $json.organization.founded_year }}",
            "Org Facebook": "={{ $json.organization.facebook_url }}",
            "Org Linkedin": "={{ $json.organization.linkedin_url }}",
            "Contact State": "={{ $json.state }}",
            "Phone Numbers": "={{ $json.organization.primary_phone?.sanitized_number }}",
            "Organization_id": "={{ $json.organization.id }}",
            "Contact  Country": "={{ $json.country }}",
            "contact Linkedin": "={{ $json.linkedin_url }}",
            "Organization_Name": "={{ $json.organization.name }}"
          },
          "schema": [
            {
              "id": "Apollo id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Apollo id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "First Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "First Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Full Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Full Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "contact Linkedin",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "contact Linkedin",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact City",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact City",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact State",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact State",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact  Country",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact  Country",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Organization_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Organization_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Phone Numbers",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Phone Numbers",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Founded year",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Founded year",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Organization_Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Organization_Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Org Linkedin",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Org Linkedin",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Org Facebook",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Org Facebook",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Org Twitter",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Org Twitter",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1s6RZnRnuOL9LSJ1SogYV7vfon-ONxCNWJGMtTPl9rjU/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1s6RZnRnuOL9LSJ1SogYV7vfon-ONxCNWJGMtTPl9rjU",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1s6RZnRnuOL9LSJ1SogYV7vfon-ONxCNWJGMtTPl9rjU/edit?usp=drivesdk",
          "cachedResultName": "Apollo Leads"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c23c0d2c-64cb-42e9-a253-164fc6bee089",
      "name": "Extract Pagination Info",
      "type": "n8n-nodes-base.set",
      "position": [
        -816,
        832
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "fe276499-6bdb-47eb-bf22-af499038a3a6",
              "name": "current_page",
              "type": "number",
              "value": "={{ $json.pagination.page }}"
            },
            {
              "id": "81b6add1-c2d5-4bc1-a076-ae69371014aa",
              "name": "total_pages",
              "type": "number",
              "value": "={{ $json.pagination.total_pages }}"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 3.4
    },
    {
      "id": "bab50260-20ee-4335-b25e-881a4603dc87",
      "name": "Increment Page",
      "type": "n8n-nodes-base.set",
      "position": [
        -368,
        832
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "35fb246d-34d8-43aa-9ae1-6ddf739ecb92",
              "name": "current_page",
              "type": "number",
              "value": "={{ $json.current_page + 1 }}"
            },
            {
              "id": "ecb5a01e-7a53-43e9-a401-90b1abd94ce7",
              "name": "base_filters",
              "type": "object",
              "value": "={{ $('Build API Filters').first().json.base_filters }}"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 3.4
    },
    {
      "id": "b4ae43e3-7b32-4287-9357-6dcad900f825",
      "name": "Rate Limit Delay",
      "type": "n8n-nodes-base.wait",
      "position": [
        -192,
        832
      ],
      "parameters": {
        "amount": 2
      },
      "executeOnce": true,
      "typeVersion": 1.1
    },
    {
      "id": "2e768935-3b15-4ac5-aeb4-9c77d4912905",
      "name": "Has More Pages?",
      "type": "n8n-nodes-base.if",
      "position": [
        -592,
        832
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "16a4c7df-c769-495b-8d69-c89a0f840b54",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.current_page < $json.total_pages }}",
              "rightValue": ""
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 2.3
    },
    {
      "id": "7b13c400-8d3c-4697-94e0-b722b1793daf",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2304,
        496
      ],
      "parameters": {
        "width": 480,
        "height": 528,
        "content": "## Apollo.io Lead Scraper\n\n### How it works\n\n1. Converts any standard Apollo.io search URL into an API-ready JSON payload.\n2. Automatically maps standard URL filters (titles, locations, employees, etc.) to the API structure.\n3. Fetches leads from the `/v1/mixed_people/search` endpoint.\n4. Extracts the contact records and appends them directly to Google Sheets.\n5. Handles pagination and rate limits automatically (2s delay) to scrape all pages safely.\n\n### Setup steps\n\n- [ ] Generate an API Key in your Apollo.io developer settings.\n- [ ] Add the key to the `APOLLO_API_KEY` environment variable or credentials.\n- [ ] Authenticate the Google Sheets node and select your specific spreadsheet.\n- [ ] Go to Apollo.io, build your search, copy the URL, and paste it into the 'Input' node."
      },
      "typeVersion": 1
    },
    {
      "id": "3b10219c-0567-4bd6-95cb-53b65e28e3a1",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1776,
        688
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 304,
        "content": "## 1. Setup & Parse Input\n\nPaste your Apollo search URL into the **Input (Set) node**. This should be the exact leads search URL you want to extract data from.\n\n\u26a0\ufe0f Set the **start_page** value to control where the workflow begins. For example, if you set `start_page = 5`, the workflow will skip earlier pages and start from page 5."
      },
      "typeVersion": 1
    },
    {
      "id": "f7a723bc-7abe-413d-829c-06c8b125c96f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1120,
        640
      ],
      "parameters": {
        "color": 7,
        "height": 352,
        "content": "## 2. API Request\n\n\ud83d\ude80 Sends a paginated **POST request** to the Apollo Search API.\n\n\ud83d\udd11 **Important:** Replace `APOLLO_API_KEY` in the headers with your actual Apollo API key."
      },
      "typeVersion": 1
    },
    {
      "id": "87df94b9-9be1-4660-b607-196a6e95019a",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -768,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 464,
        "height": 304,
        "content": "## 3. Extract & Export\n\nIsolates the 'people' array from the API response and maps the data (Name, LinkedIn, Company, etc.) to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "6276f1cf-f9a8-4c25-9c89-399f08891bd6",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        576
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 432,
        "content": "## 4. Pagination Control\n\n\u26a0\ufe0f In the **Extract Pagination Info** node, you control how many pages are processed.\n\nBy default, the workflow uses the detected `total_pages` from Apollo.\n\n\u2757 If you do **not** want all pages:\n- Remove the expression for `total_pages`  \n- Set a fixed page limit manually  \n\n\ud83c\udfaf This lets you extract only up to a specific page (e.g., first 10 pages).\n\n\ud83d\udd01 The workflow will loop only until your defined limit, not the full dataset."
      },
      "typeVersion": 1
    },
    {
      "id": "90c2c5ab-aa88-4cc6-bb2c-9369605619d7",
      "name": "Apollo Search Input",
      "type": "n8n-nodes-base.set",
      "position": [
        -1488,
        832
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "285f3c26-d8e5-42a7-8104-506a4863fb1d",
              "name": "url",
              "type": "string",
              "value": "https://app.apollo.io/#/people?sortByField=recommendations_score&sortAscending=false&organizationIndustryTagIds[]=5567cd467369644d39040000&includedOrganizationKeywordFields[]=tags&includedOrganizationKeywordFields[]=name&organizationNumEmployeesRanges[]=%2C300&personLocations[]=United%20States&excludedOrganizationKeywordFields[]=tags&excludedOrganizationKeywordFields[]=name&excludedOrganizationKeywordFields[]=social_media_description&contactEmailStatusV2[]=verified&qOrganizationKeywordTags[]=Affiliate%20marketing&qOrganizationKeywordTags[]=Affiliate%20agency&qOrganizationKeywordTags[]=Affiliate%20management&qOrganizationKeywordTags[]=Performance%20marketing&qOrganizationKeywordTags[]=Affiliate%20program%20management&qOrganizationKeywordTags[]=Partner%20marketing&qOrganizationKeywordTags[]=CPA%20marketing&qOrganizationKeywordTags[]=Performance%20affiliate&qOrganizationKeywordTags[]=Digital%20affiliate&qOrganizationKeywordTags[]=Affiliate%20network&qOrganizationKeywordTags[]=Partner%20management&qOrganizationKeywordTags[]=Revenue%20share%20marketing&qOrganizationKeywordTags[]=Commission-based%20marketing&qOrganizationKeywordTags[]=Affiliate%20optimization&personTitles[]=Founder&personTitles[]=Co-Founder&personTitles[]=CEO&personTitles[]=Chief%20Executive%20Officer&personTitles[]=President&personTitles[]=Owner&personTitles[]=Managing%20Director&personTitles[]=Managing%20Partner&personTitles[]=Chief%20Operating%20Officer&personTitles[]=COO&personTitles[]=VP%20of%20Sales&personTitles[]=Vice%20President%20of%20Sales&personTitles[]=Director%20of%20Sales&personTitles[]=Head%20of%20Sales&personTitles[]=Partner&personTitles[]=Chief%20Revenue%20Officer&personTitles[]=CRO&personTitles[]=VP%20of%20Business%20Development&personTitles[]=Head%20of%20Business%20Development&personTitles[]=Commercial%20Director&personTitles[]=Head%20of%20Growth&personTitles[]=Director%20of%20Growth&personTitles[]=VP%20of%20Growth&personTitles[]=Head%20of%20Partnerships&personTitles[]=Director%20of%20Partnerships&personTitles[]=VP%20of%20Partnerships&personTitles[]=Head%20of%20Affiliate%20Marketing&personTitles[]=VP%20of%20Affiliate%20Marketing&personTitles[]=Director%20of%20Affiliate%20Marketing&personTitles[]=Head%20of%20Partner%20Management&personTitles[]=VP%20of%20Partner%20Management&personTitles[]=Affiliate%20Manager&personTitles[]=Senior%20Affiliate%20Manager&personTitles[]=Affiliate%20Marketing%20Manager&personTitles[]=Partner%20Manager&personTitles[]=Head%20of%20Affiliate%20Operations&personTitles[]=Director%20of%20Affiliate%20Operations&personTitles[]=Affiliate%20Program%20Manager&personTitles[]=Performance%20Marketing%20Manager&qNotOrganizationKeywordTags[]=SEO%20agency&qNotOrganizationKeywordTags[]=Content%20marketing%20agency&qNotOrganizationKeywordTags[]=Web%20design&qNotOrganizationKeywordTags[]=PR%20agency&qNotOrganizationKeywordTags[]=Branding%20agency&qNotOrganizationKeywordTags[]=Creative%20studio&qNotOrganizationKeywordTags[]=Social%20media%20management&qNotOrganizationKeywordTags[]=Recruiting&qNotOrganizationKeywordTags[]=Staffing&qNotOrganizationKeywordTags[]=Software%20development&includeSimilarTitles=false&page=1"
            },
            {
              "id": "3bc0f265-4fc9-479a-a245-73c4ff96127e",
              "name": "start_page",
              "type": "string",
              "value": "1"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2f539704-2ef6-45dd-b2f1-c799870ec870",
      "name": "Build API Filters",
      "type": "n8n-nodes-base.code",
      "position": [
        -1264,
        832
      ],
      "parameters": {
        "jsCode": "// ============================================================\n// Apollo.io URL \u2192 API JSON Body Converter\n// Production-level | Drops unsupported params automatically\n// ============================================================\n\nconst input = $input.first().json;\nconst apolloUrl = input.url;\nconst startPage = parseInt(input.start_page, 10) || 1;\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 1: Extract query string from Apollo URL\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nlet queryString = '';\n\nif (apolloUrl.includes('#')) {\n  const hashPart = apolloUrl.split('#')[1] || '';\n  queryString = hashPart.includes('?') ? hashPart.split('?')[1] : '';\n} else if (apolloUrl.includes('?')) {\n  queryString = apolloUrl.split('?')[1];\n}\n\nif (!queryString) {\n  throw new Error('No query parameters found in URL: ' + apolloUrl);\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 2: Parse all URL params into a map\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst params = {};\n\nfor (const part of queryString.split('&')) {\n  if (!part) continue;\n  const eqIndex = part.indexOf('=');\n  if (eqIndex === -1) continue;\n  const rawKey = part.substring(0, eqIndex);\n  const rawVal = decodeURIComponent(part.substring(eqIndex + 1).replace(/\\+/g, ' '));\n  const key = rawKey.replace(/\\[\\]$/, '').replace(/\\[/g, '[');\n  if (!params[key]) params[key] = [];\n  params[key].push(rawVal);\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 3: SUPPORTED API parameters map\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst SUPPORTED = {\n  'personTitles':                          { key: 'person_titles',                           type: 'array' },\n  'personNotTitles':                       { key: 'person_not_titles',                       type: 'array' },\n  'personLocations':                       { key: 'person_locations',                        type: 'array' },\n  'personSeniorities':                     { key: 'person_seniorities',                      type: 'array' },\n  'organizationLocations':                 { key: 'organization_locations',                  type: 'array' },\n  'organizationIds':                       { key: 'organization_ids',                        type: 'array' },\n  'notOrganizationIds':                    { key: 'not_organization_ids',                    type: 'array' },\n  'organizationNumEmployeesRanges':        { key: 'organization_num_employees_ranges',       type: 'array' },\n  'organizationIndustryTagIds':            { key: 'organization_industry_tag_ids',           type: 'array' },\n  'organizationNotIndustryTagIds':         { key: 'organization_not_industry_tag_ids',       type: 'array' },\n  'contactEmailStatusV2':                  { key: 'contact_email_status',                    type: 'array' },\n  'qOrganizationKeywordTags':              { key: 'q_organization_keyword_tags',             type: 'array' },\n  'qNotOrganizationKeywordTags':           { key: 'q_not_organization_keyword_tags',         type: 'array' },\n  'includedOrganizationKeywordFields':     { key: 'included_organization_keyword_fields',    type: 'array' },\n  'excludedOrganizationKeywordFields':     { key: 'excluded_organization_keyword_fields',    type: 'array' },\n  'qOrganizationDomainsList':              { key: 'q_organization_domains_list',             type: 'array' },\n  'currentlyUsingAllOfTechnologyUids':     { key: 'currently_using_all_of_technology_uids',  type: 'array' },\n  'currentlyUsingAnyOfTechnologyUids':     { key: 'currently_using_any_of_technology_uids',  type: 'array' },\n  'currentlyNotUsingAnyOfTechnologyUids':  { key: 'currently_not_using_any_of_technology_uids', type: 'array' },\n  'qOrganizationJobTitles':                { key: 'q_organization_job_titles',               type: 'array' },\n  'organizationJobLocations':              { key: 'organization_job_locations',              type: 'array' },\n  'existFields':                           { key: 'exist_fields',                            type: 'array' },\n  'marketSegments':                        { key: 'market_segments',                         type: 'array' },\n  'qPersonPersonaIds':                     { key: 'q_person_persona_ids',                    type: 'array' },\n  'qKeywords':                             { key: 'q_keywords',                              type: 'string' },\n  'qPersonTitle':                          { key: 'q_person_title',                          type: 'string' },\n  'qOrganizationSearchListId':             { key: 'q_organization_search_list_id',           type: 'string' },\n  'sortByField':                           { key: 'sort_by_field',                           type: 'string' },\n  'sortAscending':                         { key: 'sort_ascending',                          type: 'boolean' },\n  'includeSimilarTitles':                  { key: 'include_similar_titles',                  type: 'boolean' },\n  'revenueRange[min]':                     { key: 'revenue_range',                           type: 'range_min' },\n  'revenueRange[max]':                     { key: 'revenue_range',                           type: 'range_max' },\n  'personTotalYoeRange[min]':              { key: 'person_total_yoe_range',                  type: 'range_min' },\n  'personTotalYoeRange[max]':              { key: 'person_total_yoe_range',                  type: 'range_max' },\n  'organizationNumJobsRange[min]':         { key: 'organization_num_jobs_range',             type: 'range_min' },\n  'organizationNumJobsRange[max]':         { key: 'organization_num_jobs_range',             type: 'range_max' },\n  'organizationJobPostedAtRange[min]':     { key: 'organization_job_posted_at_range',        type: 'range_min' },\n  'organizationJobPostedAtRange[max]':     { key: 'organization_job_posted_at_range',        type: 'range_max' },\n};\n\nconst UNSUPPORTED_DROP = new Set([\n  'contactEmailStatus', 'organizationKeywordTags', 'personFunctions',\n  'prospectedByCurrentTeam', 'isLikelyToEngage', 'emailStatus',\n  'listId', 'tableView', 'viewMode', 'activeTab', 'page', 'perPage'\n]);\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 4: Build the base filters (NO page)\n// page is excluded here \u2014 loop controls it\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst baseFilters = {};\nconst dropped = [];\nconst rangeBuffer = {};\n\nfor (const [urlKey, values] of Object.entries(params)) {\n  const match = SUPPORTED[urlKey];\n\n  if (!match) {\n    dropped.push({\n      param: urlKey,\n      reason: UNSUPPORTED_DROP.has(urlKey)\n        ? 'UI-only filter, not supported by API'\n        : 'Unknown parameter \u2014 not in API docs'\n    });\n    continue;\n  }\n\n  const { key, type } = match;\n\n  if (type === 'array') {\n    baseFilters[key] = values.map(v => v.trim()).filter(v => v !== '');\n  } else if (type === 'string') {\n    baseFilters[key] = values[0];\n  } else if (type === 'boolean') {\n    const val = values[0].toLowerCase();\n    baseFilters[key] = val === 'true' || val === '1';\n  } else if (type === 'range_min') {\n    if (!rangeBuffer[key]) rangeBuffer[key] = {};\n    rangeBuffer[key].min = isNaN(Number(values[0])) ? values[0] : Number(values[0]);\n  } else if (type === 'range_max') {\n    if (!rangeBuffer[key]) rangeBuffer[key] = {};\n    rangeBuffer[key].max = isNaN(Number(values[0])) ? values[0] : Number(values[0]);\n  }\n}\n\nfor (const [rangeKey, rangeVal] of Object.entries(rangeBuffer)) {\n  baseFilters[rangeKey] = rangeVal;\n}\n\n// Always set per_page\nbaseFilters.per_page = 100;\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 5: Output\n// current_page is what the loop will use\n// base_filters has everything EXCEPT page\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nreturn [{\n  json: {\n    base_filters: baseFilters,\n    current_page: startPage,\n    total_pages: null,\n    source_url: apolloUrl,\n    dropped_params: dropped,\n    total_dropped: dropped.length\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "73ecfeab-fac4-4f80-9e0f-7373a4ca419e",
      "name": "Fetch Leads (Apollo)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1040,
        832
      ],
      "parameters": {
        "url": "https://api.apollo.io/api/v1/mixed_people/search",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify(Object.assign({}, $json.base_filters, { page: $json.current_page })) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Cache-Control",
              "value": "no-cache"
            },
            {
              "name": "accept",
              "value": "application/json"
            },
            {
              "name": "X-Api-Key",
              "value": "APOLLO_API_KEY"
            }
          ]
        }
      },
      "typeVersion": 4.2
    }
  ],
  "connections": {
    "Extract People": {
      "main": [
        [
          {
            "node": "Write to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Increment Page": {
      "main": [
        [
          {
            "node": "Rate Limit Delay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has More Pages?": {
      "main": [
        [
          {
            "node": "Increment Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit Delay": {
      "main": [
        [
          {
            "node": "Fetch Leads (Apollo)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build API Filters": {
      "main": [
        [
          {
            "node": "Fetch Leads (Apollo)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apollo Search Input": {
      "main": [
        [
          {
            "node": "Build API Filters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Leads (Apollo)": {
      "main": [
        [
          {
            "node": "Extract People",
            "type": "main",
            "index": 0
          },
          {
            "node": "Extract Pagination Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Pagination Info": {
      "main": [
        [
          {
            "node": "Has More Pages?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Apollo Search Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Stop manually downloading CSVs or risking account bans with sketchy UI scrapers! This workflow bridges the gap between Apollo.io's powerful search filters and your Google Sheets database using Apollo's official REST API.

Source: https://n8n.io/workflows/15176/ — original creator credit. Request a take-down →

More Marketing & Ads workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Marketing & Ads

This n8n workflow automates the process of finding ecommerce seller leads, enriching them with product and business details, discovering company websites, and extracting contact information such as em

Google Sheets, N8N Nodes Mrscraper, HTTP Request
Marketing & Ads

This template is for B2B sales teams, SDRs, growth marketers, and founders who maintain a spreadsheet of prospects and need verified contact details -- emails and mobile numbers -- without manual rese

Google Sheets, HTTP Request
Marketing & Ads

This workflow finds local businesses from Google Maps and automatically enriches them with emails, social profiles, AI summaries, and personalized outreach messages — all saved to Google Sheets. Searc

HTTP Request, Google Sheets
Marketing & Ads

This workflow leverages n8n to perform automated Google Maps API queries and manage data efficiently in Google Sheets. It's designed to extract specific location data based on a given list of ZIP code

Execute Workflow Trigger, Stop And Error, HTTP Request +1
Marketing & Ads

This repository contains an SLA-based lead routing workflow built in n8n, designed to ensure fast lead response, fair sales distribution, and controlled escalation without relying on a full CRM system

Form Trigger, Google Sheets, Slack +1