{
  "id": "FXH3iheVDhMKnGyN",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Scrape LinkedIn Jobs with Apify, save to Google Sheets & email via Gmail",
  "tags": [],
  "nodes": [
    {
      "id": "02a34e91-d6e6-4c2b-a5d9-cc93caa39d59",
      "name": "Send a message",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1056,
        384
      ],
      "parameters": {
        "message": "=<h2> Job summary for {{ $now.format('dd MMMM yyyy') }}</h2>\n\n\n{{ $json.data.map(item => item.html).join('<br/>') }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=Job summary for {{ $now.format('dd MMMM yyyy')}}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "bf2ff9e4-cc09-47ef-97e5-ef5d949c3825",
      "name": "Get LinkedIn jobs",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        192,
        384
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "KE649tixwpoRnZtJJ",
          "cachedResultUrl": "https://console.apify.com/actors/KE649tixwpoRnZtJJ/input",
          "cachedResultName": "LinkedIn Jobs Scraper - No Cookies (apimaestro/linkedin-jobs-scraper-api)"
        },
        "operation": "Run actor and get dataset",
        "customBody": "{\n    \"date_posted\": \"day\",\n    \"keywords\": \"SEO manager\",\n    \"limit\": 10,\n    \"location\": \"United States\",\n    \"sort\": \"recent\"\n}"
      },
      "credentials": {
        "apifyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b1d89bb8-2fe9-4cbf-94f6-4a9c989be91f",
      "name": "Set job data & HTML",
      "type": "n8n-nodes-base.code",
      "position": [
        480,
        384
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const company = $input.item.json.company;\nconst job_title = $input.item.json.job_title;\nconst job_url = $input.item.json.job_url;\nconst location = $input.item.json.location;\nconst work_type = $input.item.json.work_type ? $input.item.json.work_type : 'Not specified';\nconst salary = $input.item.json.salary ? $input.item.json.salary : \"Not specified\";\n\nconst html_item = `<b><a href=\"${job_url}\">${job_title} - ${company}</a></b><br />Salary: ${salary} <br />Location: ${location} <br />Remote or on-site: ${work_type} <br />`;\n\nreturn {\n  json: {\n    html: html_item,\n  },\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "16e9e8d9-9b4c-40ad-b005-a13dd0536d3d",
      "name": "Combine items into one list",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        768,
        384
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "664e0abe-6144-414c-af24-ead89d6461ba",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        112,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 784,
        "content": "## Get LinkedIn jobs\nUse Apify to scrape LinkedIn jobs. This workflow uses the [`LinkedIn Jobs Scraper - No Cookies`](https://apify.com/apimaestro/linkedin-jobs-scraper-api`) actor on Apify.\n\nNote that you can use a HTTP node instead of the Apify community node."
      },
      "typeVersion": 1
    },
    {
      "id": "2be1eebd-c624-47b5-b1b6-4882331165ae",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        400,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 784,
        "content": "## Set job data and HTML and add to Google Sheets\nAdd the jobs to a Google Sheet so we can reference them at a later date\n\nAt the same time, we use a code node to set the data we want to use in the email. We format the data using HTML so it looks nice in our email."
      },
      "typeVersion": 1
    },
    {
      "id": "1e219262-b334-4a0e-abac-54cb03ff2740",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        688,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 784,
        "content": "## Combine items into one list\nWe combine all the different items into one big list"
      },
      "typeVersion": 1
    },
    {
      "id": "8f2413c7-0d59-4b9b-be72-e061a5966861",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        976,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 784,
        "content": "## Send email\nWe send an email with a list of all the jobs titles, salaries, and more"
      },
      "typeVersion": 1
    },
    {
      "id": "ba3571ef-7865-4e05-a246-622ce08e0e5d",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -176,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 784,
        "content": "## Scheduled trigger\nRun this workflow every day at noon"
      },
      "typeVersion": 1
    },
    {
      "id": "05d9eab8-5ddf-4bbe-af11-65ec78418f25",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -784,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 576,
        "height": 1200,
        "content": "## Overview\nEvery day, this workflow scrapes LinkedIn jobs based on your keywords, saves them in a Google Sheet, and sends them by email.\n\n## How it works\n- The workflow runs every day at noon.\n- The Apify node sends a request to a LinkedIn scraper actor on Apify, which scrapes and returns the data.\n- The code node formats the data we want and builds the HTML needed to make the emails look good. We use inline if statements for cases where the salary isn't listed or the job doesn\u2019t say if it\u2019s on-site, remote, or hybrid.\n- At the same time, we add the LinkedIn jobs we scraped to a Google Sheet so we can check them later.\n- We combine everything into one list.\n- The Gmail node uses the `map()` function to list all the items we scraped and formatted. It customizes the subject line and heading of the email to include the current date.\n\n## Setup steps\n1. Create a new Google Sheet and add the headers you want. Adjust the Google Sheets node to use your newly created Sheet.\n2. Customize the JSON in the `Get LinkedIn jobs` node. Note that this workflow currently uses the [`LinkedIn Jobs Scraper - No Cookies`](https://apify.com/apimaestro/linkedin-jobs-scraper-api) actor on Apify.  \n   - Leave `date_posted` as is.  \n   - Adjust `keywords` to change the job you want to scrape. You can use Boolean operators like AND or NOT in your search.  \n   - Adjust `limit` to the number of jobs you want to scrape.  \n   - Adjust `location` to match your location.  \n   - Leave `sort` as is to get the most recent jobs first.  \n3. *(Optional)* Edit the HTML in the code node to change how the listings will look in the email.  \n4. Add your email to the Gmail node.\n\n## Requirements\n- [Apify account](https://apify.com/)  \n- Apify community node installed. If you don\u2019t want to install the community node, you can use a regular HTTP node and call the HTTP directly. Check [their API docs](https://docs.apify.com/api/v2) to see what endpoint to call.  \n- Google Sheets API enabled in Google Cloud Console and credentials added to n8n\n- Gmail API enabled in Google Cloud Console credentials added to n8n\n\n## Possible customizations\n- Add full job descriptions to the Google Sheet and email  \n- Continue the flow to create a tailored CV for each job  \n- Use AI to read the job descriptions and pull out the key skills the job posting is asking for  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "27e07561-4655-40bd-aa34-655bfdd3f7f3",
      "name": "Every day at noon...",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -96,
        384
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 12
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "15b0b714-b0e8-4545-b069-076b35566605",
      "name": "Add jobs to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        480,
        208
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.posted_at.toDateTime().format('dd MMM yyyy') }}",
            "salary": "={{ $json.salary ? $json.salary : \"Not specified\" }}",
            "company": "={{ $json.company }}",
            "job url": "={{ $json.job_url }}",
            "location": "={{ $json.location ? $json.location : \"Not specified\" }}",
            "job title": "={{ $json.job_title }}",
            "remote or on-site": "={{ $json.work_type ? $json.work_type : \"Not specified\" }}"
          },
          "schema": [
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "job title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "job title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "company",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "company",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "job url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "job url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "salary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "salary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "remote or on-site",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "remote or on-site",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "location",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "useAppend": true
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IYZk-wt5AUgdJmRcnoA04X23flLyTeyG3AeTsAfWs1U/edit#gid=0",
          "cachedResultName": "Jobs"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1IYZk-wt5AUgdJmRcnoA04X23flLyTeyG3AeTsAfWs1U",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1IYZk-wt5AUgdJmRcnoA04X23flLyTeyG3AeTsAfWs1U/edit?usp=drivesdk",
          "cachedResultName": "Linkedin jobs - n8n demo"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7f4b0a6a-a5b1-4ceb-b438-7fea120b0d53",
  "connections": {
    "Get LinkedIn jobs": {
      "main": [
        [
          {
            "node": "Set job data & HTML",
            "type": "main",
            "index": 0
          },
          {
            "node": "Add jobs to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set job data & HTML": {
      "main": [
        [
          {
            "node": "Combine items into one list",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every day at noon...": {
      "main": [
        [
          {
            "node": "Get LinkedIn jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine items into one list": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}