This workflow follows the HTTP Request → Postgres 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 →
{
"name": "AusJobTracker - Daily Job Scraper",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 24,
"triggerAtHour": 8
}
]
}
},
"id": "schedule-trigger",
"name": "Daily 8AM Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
0
]
},
{
"parameters": {
"actorId": "bebity/linkedin-jobs-scraper",
"runInput": "={{ JSON.stringify({\n \"searchQueries\": [\n \"computational biology Australia\",\n \"bioinformatics Australia\",\n \"genomics Australia\",\n \"bioinformatician Australia\"\n ],\n \"location\": \"Australia\",\n \"maxItems\": 50,\n \"scrapeJobDetails\": true\n}) }}",
"options": {
"waitForFinish": true,
"timeout": 300
}
},
"id": "apify-linkedin",
"name": "Apify LinkedIn Jobs",
"type": "n8n-nodes-base.apify",
"typeVersion": 1,
"position": [
220,
0
],
"credentials": {
"apifyApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Process and score job listings\nconst primaryKeywords = [\n 'computational biology', 'bioinformatics', 'bacterial genomics',\n 'microbial genomics', 'antibiotic resistance', 'microbial evolution',\n 'genomics', 'sequencing data analysis', 'computational biologist',\n 'bioinformatician', 'genome analysis', 'bacterial evolution',\n 'crop genomics', 'plant genomics', 'agricultural genomics'\n];\n\nconst secondaryKeywords = [\n 'plant biology', 'environmental microbiology', 'pharmacology',\n 'systems biology', 'computational scientist', 'data scientist',\n 'research scientist', 'postdoctoral', 'fellowship', 'microbiology',\n 'metagenomics', 'crop science'\n];\n\nconst australianLocations = [\n 'australia', 'melbourne', 'sydney', 'brisbane', 'adelaide',\n 'perth', 'canberra', 'hobart', 'darwin', 'nsw', 'vic', 'qld',\n 'sa', 'wa', 'act', 'nt', 'tas'\n];\n\nfunction scoreJob(job) {\n let score = 0;\n const title = (job.title || '').toLowerCase();\n const description = (job.description || '').toLowerCase();\n const location = (job.location || '').toLowerCase();\n const matchedKeywords = [];\n\n // Check Australian location\n const isAustralian = australianLocations.some(loc => location.includes(loc));\n if (!isAustralian) return null;\n\n // Score primary keywords\n for (const keyword of primaryKeywords) {\n if (title.includes(keyword)) {\n score += 15;\n matchedKeywords.push(keyword);\n } else if (description.includes(keyword)) {\n score += 10;\n matchedKeywords.push(keyword);\n }\n }\n\n // Score secondary keywords\n for (const keyword of secondaryKeywords) {\n if (title.includes(keyword)) {\n score += 7;\n matchedKeywords.push(keyword);\n } else if (description.includes(keyword)) {\n score += 5;\n matchedKeywords.push(keyword);\n }\n }\n\n // Minimum score threshold\n if (score < 10) return null;\n\n return {\n title: job.title,\n organization: job.company || job.companyName || 'Unknown',\n location: job.location,\n description: job.description || '',\n brief_description: (job.description || '').substring(0, 500),\n url: job.link || job.url || job.jobUrl,\n source_website: 'linkedin.com',\n date_posted: job.postedAt || job.datePosted || null,\n job_type: job.employmentType || job.jobType || null,\n sector: 'private',\n relevance_score: score,\n keywords_matched: JSON.stringify([...new Set(matchedKeywords)]),\n raw_data: JSON.stringify(job),\n is_active: true\n };\n}\n\n// Process all items\nconst results = [];\nfor (const item of $input.all()) {\n const job = item.json;\n const scored = scoreJob(job);\n if (scored) {\n results.push({ json: scored });\n }\n}\n\nreturn results;"
},
"id": "process-jobs",
"name": "Score & Filter Jobs",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
440,
0
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, url FROM jobs WHERE url = '{{ $json.url }}' LIMIT 1",
"options": {}
},
"id": "check-duplicate",
"name": "Check Duplicate",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
660,
0
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "is-new-job",
"leftValue": "={{ $json.length }}",
"rightValue": "0",
"operator": {
"type": "number",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-new-job",
"name": "Is New Job?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
880,
0
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO jobs (title, organization, location, description, brief_description, url, source_website, date_posted, job_type, sector, relevance_score, keywords_matched, raw_data, is_active, date_discovered)\nVALUES (\n '{{ $('Score & Filter Jobs').item.json.title.replace(/'/g, \"''\") }}',\n '{{ $('Score & Filter Jobs').item.json.organization.replace(/'/g, \"''\") }}',\n '{{ $('Score & Filter Jobs').item.json.location.replace(/'/g, \"''\") }}',\n '{{ $('Score & Filter Jobs').item.json.description.replace(/'/g, \"''\").substring(0, 10000) }}',\n '{{ $('Score & Filter Jobs').item.json.brief_description.replace(/'/g, \"''\") }}',\n '{{ $('Score & Filter Jobs').item.json.url }}',\n '{{ $('Score & Filter Jobs').item.json.source_website }}',\n {{ $('Score & Filter Jobs').item.json.date_posted ? \"'\" + $('Score & Filter Jobs').item.json.date_posted + \"'\" : 'NULL' }},\n {{ $('Score & Filter Jobs').item.json.job_type ? \"'\" + $('Score & Filter Jobs').item.json.job_type + \"'\" : 'NULL' }},\n '{{ $('Score & Filter Jobs').item.json.sector }}',\n {{ $('Score & Filter Jobs').item.json.relevance_score }},\n '{{ $('Score & Filter Jobs').item.json.keywords_matched }}',\n '{{ $('Score & Filter Jobs').item.json.raw_data.replace(/'/g, \"''\").substring(0, 50000) }}',\n true,\n NOW()\n)\nRETURNING id, title, organization, location",
"options": {}
},
"id": "insert-job",
"name": "Insert New Job",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1100,
-100
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Aggregate all new jobs for email\nconst newJobs = $input.all().map(item => item.json);\n\nif (newJobs.length === 0) {\n return [{ json: { skipEmail: true, count: 0 } }];\n}\n\n// Build email body\nconst jobList = newJobs.map(job => \n `<div style=\"margin-bottom: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 8px;\">\n <h3 style=\"margin: 0 0 10px 0; color: #2563eb;\">${job.title}</h3>\n <p style=\"margin: 5px 0; color: #666;\"><strong>${job.organization}</strong> - ${job.location}</p>\n <p style=\"margin: 10px 0; font-size: 14px;\">${(job.brief_description || '').substring(0, 200)}...</p>\n <a href=\"${job.url}\" style=\"color: #2563eb; text-decoration: none;\">View Job \u2192</a>\n </div>`\n).join('');\n\nconst emailBody = `\n<html>\n<body style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 600px; margin: 0 auto;\">\n <h1 style=\"color: #1e40af;\">\ud83e\uddec New Computational Biology Jobs</h1>\n <p style=\"color: #666;\">Found ${newJobs.length} new job(s) matching your criteria:</p>\n ${jobList}\n <hr style=\"border: none; border-top: 1px solid #ddd; margin: 30px 0;\">\n <p style=\"color: #999; font-size: 12px;\">View all jobs at <a href=\"https://ausjobtracker.vercel.app\">AusJobTracker</a></p>\n</body>\n</html>\n`;\n\nreturn [{\n json: {\n skipEmail: false,\n count: newJobs.length,\n subject: `\ud83e\uddec ${newJobs.length} New Computational Biology Job${newJobs.length > 1 ? 's' : ''} Found`,\n body: emailBody\n }\n}];"
},
"id": "aggregate-jobs",
"name": "Aggregate for Email",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1320,
-100
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "should-send-email",
"leftValue": "={{ $json.skipEmail }}",
"rightValue": "false",
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-send-email",
"name": "Should Send Email?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1540,
-100
]
},
{
"parameters": {
"method": "POST",
"url": "https://n8n.kaulfamily.org/webhook/send-email",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"to\": \"YOUR_EMAIL@example.com\",\n \"subject\": \"{{ $json.subject }}\",\n \"body\": {{ JSON.stringify($json.body) }}\n}",
"options": {}
},
"id": "send-email",
"name": "Send Email Notification",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1760,
-200
]
},
{
"parameters": {},
"id": "no-op-skip",
"name": "Skip (No New Jobs)",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
1100,
100
]
}
],
"connections": {
"Daily 8AM Trigger": {
"main": [
[
{
"node": "Apify LinkedIn Jobs",
"type": "main",
"index": 0
}
]
]
},
"Apify LinkedIn Jobs": {
"main": [
[
{
"node": "Score & Filter Jobs",
"type": "main",
"index": 0
}
]
]
},
"Score & Filter Jobs": {
"main": [
[
{
"node": "Check Duplicate",
"type": "main",
"index": 0
}
]
]
},
"Check Duplicate": {
"main": [
[
{
"node": "Is New Job?",
"type": "main",
"index": 0
}
]
]
},
"Is New Job?": {
"main": [
[
{
"node": "Insert New Job",
"type": "main",
"index": 0
}
],
[
{
"node": "Skip (No New Jobs)",
"type": "main",
"index": 0
}
]
]
},
"Insert New Job": {
"main": [
[
{
"node": "Aggregate for Email",
"type": "main",
"index": 0
}
]
]
},
"Aggregate for Email": {
"main": [
[
{
"node": "Should Send Email?",
"type": "main",
"index": 0
}
]
]
},
"Should Send Email?": {
"main": [
[
{
"node": "Send Email Notification",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": ""
},
"staticData": null,
"tags": [
{
"name": "job-scraping"
},
{
"name": "ausjobtracker"
}
],
"triggerCount": 1,
"versionId": "1"
}
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.
apifyApipostgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AusJobTracker - Daily Job Scraper. Uses apify, postgres, httpRequest. Scheduled trigger; 10 nodes.
Source: https://gist.github.com/vickaul-ai/5030663a3ca16e4a0a6166f6d9dc96a6 — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Workflow A: Loan Product Crawler. Uses httpRequest, postgres. Scheduled trigger; 4 nodes.
Problem Solved:* Small and Medium-sized IT companies often struggle to stay ahead in a rapidly evolving market. Manually tracking competitor moves, pricing changes, product updates, and emerging marke
> Watch the full Youtube Video Tutorial [](https://youtu.be/Y-wUr2-UYZk)
Very straightforward workflow. It checks the Epic Games website if the HTML container with free games has changed. If it did then it will send a notification to Discord with a list of embeds containin
This workflow automatically scrapes business leads from Google Maps on a daily schedule and ensures only high-quality, unique leads are processed. New businesses are cleaned, validated, and deduplicat