Scheduled AI-answer monitoring in n8n: a complete workflow
You can run a daily AI-visibility check without writing a service: an n8n workflow submits your prompt set every morning as async tasks, a second workflow receives each finished task at a webhook, and one row per answer lands in a sheet or database. Both workflows below use the n8n-nodes-answerline community node from npm.
What the workflow measures
An AI-visibility check runs a fixed prompt set against one or more AI engines and records, for each answer, whether your brand is named and whether your domain is cited. Keep the prompts, markets and matching rules identical every day so the numbers stay comparable. For how to choose prompts, see designing a prompt set worth monitoring; for why a single run proves little, see AI answer volatility.
Per answer, the workflow writes:
| Column | Source field |
|---|---|
date, engine, country, promptId |
your prompt list and task.taskType |
status |
task.status (COMPLETED or FAILED) |
mentioned |
brand name found in response.result.text |
cited |
your domain found in response.result.sources[].url |
firstCitedPosition |
lowest position among your matching sources |
credits |
credits.creditsCharged |
The node
Install the node in n8n under Settings > Community Nodes > Install with the package name n8n-nodes-answerline. The n8n documentation states that only users with the Owner or Admin role can install community nodes from npm on a self-hosted instance (n8n docs, GUI installation, checked 2026-09-17).
Create an Answerline API credential with three fields:
- API Key: a key from the dashboard (keys start with
sk_). It is sent asAuthorization: Bearer <key>. - Base URL:
https://api.answerline.dev. The node refuses a base URL that is nothttps://(plainhttp://localhostis allowed for local development). - Engines: the engines the node offers. The default is every engine: ChatGPT, Gemini, Perplexity, Copilot, AI Mode, Google Search, Google News and Grok.
n8n tests the credential with GET /v1/credits, which costs nothing and answers 401 for a wrong key.
The node has four operations:
| Operation | Request | Use it for |
|---|---|---|
| Run Monitor | POST /v1/monitor/{engine} |
one-off calls where the workflow can wait for the answer |
| Create Task | POST /v1/async/task |
scheduled prompt sets; takes Priority, Idempotency Key and Webhook URL |
| Get Task | GET /v1/async/task/{taskId} |
reading a task’s status and result |
| Get Credits | GET /v1/credits |
a balance check before a large run |
Run Monitor and Create Task share the query fields: Engine, Prompt or Query, Country (ISO 3166-1 alpha-2, default US) and Additional Fields (JSON) for any other request field of the engine, for example {"include": {"shopping": true}} for ChatGPT, or {"state": "CA"} for Gemini (the only engine that takes a US state). Additional fields win over the other inputs. For Google Search, a url in the additional fields replaces the query and country.
With Continue On Fail enabled, a failed item outputs error, description and httpCode instead of stopping the execution, so one bad prompt does not block the rest.
Why Create Task, not Run Monitor
A synchronous call holds the HTTP request open while the engine answers, for up to five minutes. That suits a button in a chat tool, not a prompt set. An async task returns immediately with a task.id, waits in your queue (about 100,000 typical tasks fit), and its result is posted to your webhook when it finishes. The trade-offs are covered in sync calls, async tasks or webhooks.
Workflow A: submit the prompt set
1. Schedule Trigger
Add a Schedule Trigger, interval Days, hour 7. The n8n docs note that a workflow triggered by the Schedule node must be saved and published, and that the schedule uses the workflow timezone, falling back to the instance timezone (n8n docs, Schedule Trigger, checked 2026-09-17). Set the workflow timezone explicitly so “daily at 07:00” means what you think.
2. Emit the prompt list
A Code node returns one item per prompt and market. Keep a stable promptId; it becomes part of the idempotency key and the join key in your table.
const prompts = [
{ promptId: "pm-agencies", prompt: "best project management tool for agencies" },
{ promptId: "pm-vs", prompt: "Asana vs Monday for a 20-person agency" },
{ promptId: "client-hours", prompt: "how to track billable client hours" },
];
const markets = ["US"]; // add any of the 213 countries ChatGPT answers from
return prompts.flatMap((p) =>
markets.map((country) => ({ json: { ...p, country, engine: "CHATGPT" } })),
);
If the list lives in a sheet, replace the Code node with a Google Sheets read and keep the same columns.
3. Answerline node: Create Task
Configure one Answerline node with operation Create Task:
| Field | Value |
|---|---|
| Engine | Monitor ChatGPT Responses |
| Prompt or Query | {{ $json.prompt }} |
| Country | {{ $json.country }} |
| Additional Fields (JSON) | leave empty |
| Priority | 1 |
| Idempotency Key | {{ $json.engine }}-{{ $json.country }}-{{ $json.promptId }}-{{ $now.toFormat('yyyy-MM-dd') }} |
| Webhook URL | the production URL of Workflow B’s Webhook node |
n8n runs the node once per input item, so three items create three tasks. The node sends the key both as the body’s idempotencyKey and as an Idempotency-Key header. Sending the same task with the same key again returns the task already created; a different task under that key is refused with 409 RESOURCE_CONFLICT. That is why the key is built from meaning (engine, market, prompt, day) and not from $now with a time component: a retried execution at 07:03 must produce the same key as the first attempt at 07:00. If you leave the field empty, the node builds a key from the workflow id, node id, execution id and item index, which protects Retry On Fail within one execution but not a manual re-run of the whole workflow.
Each created task comes back as { success, task: { id, taskType, status: "QUEUED", priority, createdAt, idempotencyKey }, credits: { creditsToCharge, creditsCharged: null } }. creditsToCharge is the reserved maximum, in dollars; the charge happens when the task completes, and failed tasks are not charged.
For large sets, the API also accepts up to 500 tasks in one POST /v1/async/task/batch call. The node creates one task per item, which is simpler to debug; switch to an HTTP Request node posting to the batch endpoint if request count matters.
Workflow B: receive and record results
4. Webhook node
Add a Webhook node, HTTP method POST, Respond Immediately. The API counts a delivery as successful on a 2xx answer within 15 seconds and otherwise retries, up to 10 attempts, with the last attempt about 21 to 43 minutes after the first. Responding immediately keeps slow downstream nodes from causing retries.
Use the Production URL in Workflow A. The n8n docs state the production URL is registered when the workflow is published, while the test URL only listens during a test (n8n docs, Webhook node, checked 2026-09-17). The URL must be https and publicly reachable; the API does not deliver to private addresses.
The delivered body is the same JSON GET /v1/async/task/{taskId} returns for the finished task: task (with status COMPLETED or FAILED), credits, and response, which holds the engine’s result or the error.
5. Trust, then parse
Anyone who learns the webhook URL can post to it, so either verify deliveries or treat them as notifications:
- Verify the signature. Each delivery carries
Webhook-Signature: t=<unix>,v1=<hex>, wherev1is the hex HMAC-SHA256 of<t>.<raw body>keyed with yourwhsec_secret. Verification needs the raw bytes, so enable the Webhook node’s Raw Body option and follow the webhook docs or this walkthrough. - Re-read the task. Take
task.idfrom the delivery and run the Answerline node with Get Task. The result then comes from an authenticated API call, and the delivery is only a notification. This costs one extra request per task and nothing more.
Also drop deliveries with "test": true at the top level (dashboard test sends), and deduplicate by task.id: deliveries can arrive twice or out of order.
6. Extract the row
A Code node turns the task into a row. Put your brand and domain in the first two lines.
const BRAND = /\bacme\b/i;
const DOMAIN = "acme.com";
return $input.all().map(({ json }) => {
const body = json.body ?? json; // Webhook node output vs Get Task output
const { task, credits, response } = body;
const result = response?.result ?? {};
const ours = (result.sources ?? []).filter((s) => {
try { return new URL(s.url).hostname.replace(/^www\./, "").endsWith(DOMAIN); } catch { return false; }
});
return {
json: {
taskId: task.id,
idempotencyKey: task.idempotencyKey,
engine: task.taskType,
status: task.status,
mentioned: BRAND.test(result.text ?? ""),
cited: ours.length > 0,
firstCitedPosition: ours.length ? Math.min(...ours.map((s) => s.position)) : null,
credits: credits.creditsCharged,
},
};
});
The row carries idempotencyKey rather than separate prompt and market columns. Parsing the key back apart is brittle; instead, have Workflow A write each created task’s task.id, promptId and country to a submissions table, and join on task.id.
7. Write and alert
Append the row with a Google Sheets or Postgres node. For alerts, add an IF node after a lookup of the previous day’s row for the same idempotencyKey prefix: continue only when mentioned or cited changed, then post to Slack. Alert on transitions, not on every run: answers are reworded constantly, and a raw “brand not mentioned” feed is mostly noise. Setting a monitoring cadence covers how often transitions are worth checking.
Cost of a daily run
Per-task prices at the Starter tier: ChatGPT $0.0006, Gemini $0.0006, AI Mode $0.00206, Google News $0.0002, Copilot $0.00274, Perplexity $0.0015, Grok $0.00218. ChatGPT’s include flags are free.
| Setup | Tasks per run | Price per task | Cost per run |
|---|---|---|---|
| 25 prompts, US, ChatGPT | 25 | $0.0006 | $0.015 |
| 25 prompts, US, Gemini | 25 | $0.0006 | $0.015 |
| 25 prompts, US, ChatGPT and Gemini | 50 | $0.0006 and $0.0006 | $0.03 |
A new account’s 100 free requests work on every engine: enough for 2 combined ChatGPT and Gemini runs as tasks. After that you top up your balance. See pricing for the tiers and estimating your monitoring bill for a full model. Add a Get Credits node before Create Task and stop the run when remaining is below the run’s cost, so a mid-run 403 INSUFFICIENT_CREDITS never leaves you with half a day’s data.
Pitfalls
- Test URL in a published workflow. Tasks created with the test webhook URL deliver nowhere once the test listener closes. Always paste the production URL.
- Time in the idempotency key.
{{$now}}alone changes every millisecond, so retries are charged again. Use the date. - Treating PROCESSING as final. A task can go from
PROCESSINGback toQUEUED. OnlyCOMPLETEDandFAILEDare final, which is why the webhook, not a poll loop, closes the workflow. - Ignoring FAILED. Write failed rows too, with the
responseerror, so a gap in the chart is explained. Failed tasks are not charged. - Pending-task limits. A very large submission can be rejected whole with 429
QUEUE_LIMIT_EXCEEDED. CheckGET /v1/async/statusor split the run. See handling API errors. - Brand regex too loose. “Acme” matches “Acme Corp” and “acme-like”. Test the pattern against a week of stored
textbefore you trust the rate; measuring brand mentions goes deeper.
Other uses of the node
The same node works for other automations: enrich a lead list with whether an assistant recommends each company, write the cited sources of each answer into a sheet, or run Google News queries for a weekly digest. For the use case behind this workflow, see AI visibility tracking; if your team works in Zapier instead, the Zapier alert setup covers the same pattern there.
Install steps and credentials are on the n8n integration page and in the integrations docs.
Questions
Which n8n operations does the n8n-nodes-answerline node provide?
Four: Run Monitor (a synchronous engine call), Create Task (an async task with priority, idempotency key and webhook URL), Get Task (status and result of a task) and Get Credits (the remaining balance in dollars).
How do I join a webhook delivery back to the prompt that produced it?
Have the submitting workflow write each created task's id, prompt id and market to a submissions table, then join the delivery on task.id. Parsing the idempotency key apart again is brittle, and deliveries can arrive twice or out of order, so deduplicate on task.id as well.
How do I stop a retried n8n execution from paying twice?
Set the node's Idempotency Key from what the run means, for example engine, country, prompt id and date. A resend of the same task under that key returns the task already created. If you leave it empty, the node derives a key from the workflow, node, execution and item.
How much does a daily n8n run cost?
Multiply prompts by markets by the per-task price. For example, 25 prompts in one market as ChatGPT tasks cost $0.0006 each at the Starter tier, so $0.015 per run.
Can I trust the webhook body in n8n without verifying the signature?
Treat an unverified delivery as a notification only. Either verify the Webhook-Signature header against the raw body, or take task.id from the delivery and read the result with the node's Get Task operation, which is an authenticated call to the API.