This workflow corresponds to n8n.io template #17907 — we link there as the canonical source.
This workflow follows the Apifyn8N Nodes Apify → Google Sheets 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": "Automate app store rank tracking on Google Play into Google Sheets",
"nodes": [
{
"id": "a2d5e649-0001-4b01-c001-000000000001",
"name": "Every Monday morning",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
520
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "a2d5e649-0002-4b02-c002-000000000002",
"name": "Set the keywords to track",
"type": "n8n-nodes-base.set",
"position": [
260,
520
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "a2d5e649-0011-4b11-c011-+1234567890",
"name": "keywords",
"type": "array",
"value": "[\"habit tracker\", \"daily planner\"]"
},
{
"id": "a2d5e649-0012-4b12-c012-+1234567890",
"name": "yourPackageName",
"type": "string",
"value": "org.isoron.uhabits"
},
{
"id": "a2d5e649-0013-4b13-c013-+1234567890",
"name": "appsPerKeyword",
"type": "number",
"value": "20"
},
{
"id": "a2d5e649-0014-4b14-c014-+1234567890",
"name": "country",
"type": "string",
"value": "us"
},
{
"id": "a2d5e649-0015-4b15-c015-+1234567890",
"name": "language",
"type": "string",
"value": "en"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a2d5e649-0003-4b03-c003-000000000003",
"name": "One search per keyword",
"type": "n8n-nodes-base.splitOut",
"position": [
520,
520
],
"parameters": {
"include": "allOtherFields",
"options": {},
"fieldToSplitOut": "keywords"
},
"typeVersion": 1
},
{
"id": "a2d5e649-0004-4b04-c004-000000000004",
"name": "Search the Play Store",
"type": "@apify/n8n-nodes-apify.apify",
"position": [
780,
520
],
"parameters": {
"memory": 1024,
"actorId": "johnvc~google-play-api",
"resource": "Actors",
"operation": "Run actor and get dataset",
"customBody": "={{ JSON.stringify({ search_mode: 'search', query: $json.keywords, max_results: $json.appsPerKeyword, country: $json.country, language: $json.language }) }}"
},
"typeVersion": 1
},
{
"id": "a2d5e649-0005-4b05-c005-000000000005",
"name": "Keep rows that are real apps",
"type": "n8n-nodes-base.filter",
"position": [
1040,
520
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "a2d5e649-0041-4b41-c041-+1234567890",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.resultType }}",
"rightValue": "app"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "a2d5e649-0006-4b06-c006-000000000006",
"name": "One row per ranked app",
"type": "n8n-nodes-base.code",
"position": [
1300,
520
],
"parameters": {
"jsCode": "// One row per ranked app, with your own app flagged so the sheet reads as a\n// leaderboard rather than a list. Play search returns apps in rank order, so\n// position is the ranking for that keyword on that day.\nconst cfg = $('Set the keywords to track').first().json;\nconst yours = String(cfg.yourPackageName || '').trim().toLowerCase();\nconst weekOf = $now.toFormat('yyyy-MM-dd');\n\nconst clip = (s, n) => {\n const v = String(s || '').replace(/\\s+/g, ' ').trim();\n return v.length > n ? v.slice(0, n - 3) + '...' : v;\n};\n\nreturn $input.all().map((item) => {\n const a = item.json;\n const pkg = String(a.productId || '');\n return {\n json: {\n 'Week of': weekOf,\n Keyword: a.query || '',\n Rank: a.position ?? '',\n App: clip(a.title, 120),\n 'Is your app': yours !== '' && pkg.toLowerCase() === yours ? 'YES' : '',\n Developer: clip(a.developer, 120),\n Category: a.category || '',\n Rating: typeof a.rating === 'number' ? a.rating : '',\n Downloads: a.downloads || '',\n 'Package name': pkg,\n 'Play listing': a.url || '',\n },\n };\n});\n"
},
"typeVersion": 2
},
{
"id": "a2d5e649-0007-4b07-c007-000000000007",
"name": "Append rankings to sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
1560,
520
],
"parameters": {
"columns": {
"value": {},
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "a2d5e649-0090-4b90-c090-000000000090",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-620,
40
],
"parameters": {
"width": 520,
"height": 1240,
"content": "## Automate app store rank tracking on Google Play into Google Sheets\n\nNo ASO tool subscription and no per-seat licence. Every week this searches the Play Store for the keywords you care about and appends one row per ranked app to your sheet: position, app, developer, category, rating, download band and the package name, with your own app flagged YES.\n\nBecause it records the whole ranked list and not just your position, the sheet doubles as a competitor watch: you can see exactly who moved above you and what their rating looks like.\n\n**Who's it for**\nAndroid developers watching keyword rankings after a listing change, ASO consultants reporting to clients, and anyone who wants the raw positions rather than a dashboard they rent.\n\n**How it works**\n1. A schedule trigger fires once a week\n2. One Set node holds your keywords, your package name, and the storefront\n3. The Apify node runs one Play Store search per keyword\n4. A Code node turns each result into a row and flags your own app\n\n**Setup**\n1. Create a free Apify account and add your API token to the Apify credential\n2. Connect your Google account in the Sheets node and pick a spreadsheet\n3. Replace the example keywords, and set your package name, the one after id= in your Play Store URL\n\n**Good to know**\nUnder a tenth of a cent per app returned, so three keywords at 20 apps each is about 5 cents a week.\nPlay rankings are per country, so change the storefront and you are tracking a different market entirely.\nActor: https://apify.com/johnvc/google-play-api?fpr=9n7kx3&fp_sid=n8n"
},
"typeVersion": 1
},
{
"id": "a2d5e649-0091-4b91-c091-000000000091",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-40,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 1. Schedule\nRuns every Monday morning. Change the cadence, or swap in a manual trigger while you test."
},
"typeVersion": 1
},
{
"id": "a2d5e649-0092-4b92-c092-000000000092",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 2. Your input\nKeywords, your package name, and the storefront country. This is the only node you edit."
},
"typeVersion": 1
},
{
"id": "a2d5e649-0093-4b93-c093-000000000093",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 3. Fan out\nTurns your keyword list into one Play Store search each."
},
"typeVersion": 1
},
{
"id": "a2d5e649-0094-4b94-c094-000000000094",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
740,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 4. Search\nRuns the Google Play API actor for one keyword. Add your Apify credential here."
},
"typeVersion": 1
},
{
"id": "a2d5e649-0095-4b95-c095-000000000095",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1000,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 5. Clean\nKeeps only real app rows, so an upstream error never reaches the sheet."
},
"typeVersion": 1
},
{
"id": "a2d5e649-0096-4b96-c096-000000000096",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1260,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 6. Shape\nOne row per ranked app. Your own package name is flagged YES."
},
"typeVersion": 1
},
{
"id": "a2d5e649-0097-4b97-c097-000000000097",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
1520,
60
],
"parameters": {
"color": 7,
"width": 240,
"height": 240,
"content": "### 7. Deliver\nPick your spreadsheet and tab. Columns map automatically."
},
"typeVersion": 1
},
{
"id": "a2d5e649-0080-4b80-c080-000000000080",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
860
],
"parameters": {
"color": 7,
"width": 400,
"height": 240,
"content": "### Where do I find my package name?\nIt is the value after `id=` in your Play Store URL, for example `com.spotify.music`. Paste it into the config node and your own rows get flagged YES so you can filter the sheet down to your rank history."
},
"typeVersion": 1
},
{
"id": "a2d5e649-0081-4b81-c081-000000000081",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
660,
860
],
"parameters": {
"color": 7,
"width": 400,
"height": 240,
"content": "### Rankings are per storefront\nPlay results differ by country, so `us` and `de` are two different rank histories. Duplicate the workflow per market rather than mixing them in one sheet, or add the country to the row so you can pivot on it."
},
"typeVersion": 1
}
],
"settings": {
"executionOrder": "v1"
},
"connections": {
"Every Monday morning": {
"main": [
[
{
"node": "Set the keywords to track",
"type": "main",
"index": 0
}
]
]
},
"Search the Play Store": {
"main": [
[
{
"node": "Keep rows that are real apps",
"type": "main",
"index": 0
}
]
]
},
"One row per ranked app": {
"main": [
[
{
"node": "Append rankings to sheet",
"type": "main",
"index": 0
}
]
]
},
"One search per keyword": {
"main": [
[
{
"node": "Search the Play Store",
"type": "main",
"index": 0
}
]
]
},
"Set the keywords to track": {
"main": [
[
{
"node": "One search per keyword",
"type": "main",
"index": 0
}
]
]
},
"Keep rows that are real apps": {
"main": [
[
{
"node": "One row per ranked app",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
No ASO tool subscription and no per-seat licence. Every week this searches the Play Store for your keywords and appends one row per ranked app to Google Sheets: position, app, developer, category, rating and download band, with your own app flagged. Runs every Monday at 08:00 on…
Source: https://n8n.io/workflows/17907/ — 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.
No rank tracker subscription and no SERP API key. This template checks where your business ranks in Google's local results for the keywords you choose, every week, and appends one row per listing to G
No Firecrawl API key and no OpenAI key. This template checks every week whether any member of Congress disclosed a trade in the stocks you follow, and appends one row per transaction to Google Sheets:
No Google Business Profile connection and no SerpApi or Bright Data account. This template runs weekly review tracking across the whole Google local pack for your search term, appending one row per bu
No IP watch service and no per-seat subscription. Every week this searches Google Patents for the technologies you follow and appends one row per patent to Google Sheets: title, assignee, inventor, pu
This workflow runs every Monday morning, searches Google Shopping for a list of products using Apify, summarizes credible weekly pricing metrics per product, and appends the results to a Google Sheets