An open n8n workflow that drafts FAQ blocks (plus FAQPage JSON-LD) for service
and product pages from an approved company fact base, with a
prompt-injection firewall between the public web and the model that steers
the run. Nothing publishes itself — every draft is reviewed by a human in a
Google Sheet.
Built by Eugen Ullrich. Full write-up, cost breakdown and the honest limit: eullrich.com/en/lab/n8n-faq-factory (Deutsch).
Based on Simon Willison's dual LLM pattern. The moment one model reads foreign page text and holds company data, every page becomes an instruction channel into a system that knows your data and can call tools. This workflow splits that responsibility:
- Privileged planner — decides what happens (which pages, how many FAQs, which fact categories, which tone). It only ever receives closed-vocabulary symbols: enums, counts, ids. No page text crosses that boundary.
- Quarantined extractor / writer — touch untrusted content; hold no tools and no credentials. Their output is inert data in sheet columns, never executed.
- Deterministic gates A/B/C (plain code, no model) between every hop: strict JSON schema, enum whitelists, length caps, URL/email ban, injection-pattern scan, and a grounding check — every answer must cite ids from the approved fact set it was handed, or it is
rejected.
Honest limit: the writer does read quarantined candidate questions, so wording-steering across that one hop remains possible. It reaches no tools, no company data and no publish path — the channel ends at Gate C and human review. The pattern protects tools, credentials and data — not taste.
Four phases, weekly by default:
- Collect + extract (quarantined) — fetch each active page over HTTP, strip to plain text (15k chars), extract candidate questions and claims as strict JSON. Gate A enforces schema, whitelists and pattern scans. Failing pages land as
status=error/quarantine_rejectand never stop the run. - Plan (privileged) — the planner sees symbols only (
topic_class,audience,intents, counts, fact counts per category) and returns a per-page plan. Gate B validates every field and assembles one writer job per page — the single place where quarantined variables and approved facts merge. - Write + review (quarantined) — the writer answers only from the numbered facts and cites their ids. Gate C rejects ungrounded answers, links, email addresses and injection patterns, dedupes and flags odd lengths. Drafts land as
status=review; a digest email carries per-page tables, fact gaps and a JSON-LD preview. - Publish (manual, separate) — a human sets
status=approved; the publish flow buildsFAQPageJSON-LD per page and POSTs to your CMS webhook, then marks rowspublished.
| Tab | Columns |
|---|---|
pages (you fill) |
page_id, url, page_type, language, active |
company_facts (you fill) |
fact_id, category, fact_text, source, approved — only approved=TRUE ever reaches a model |
extractions (workflow fills) |
raw signals per run, incl. quarantine rejections |
faq_drafts (workflow drafts, human reviews) |
… question, answer, fact_ids, status, flag, reviewer_note |
category must be one of: pricing, features, integration, implementation,
support, security, compliance, delivery, warranty, training, general. A
fact_gap row marks a question no approved fact could answer — add the fact
and rerun. Status flow: review → approved | rejected → published.
- Import
faq-factory.workflow.jsoninto n8n. - Create the Google Sheet with the four tabs above; fill
pagesandcompany_facts. - HTTP Header Auth credential for OpenRouter: header
Authorization, valueBearer sk-or-v1-...(openrouter.ai/keys). - Assign a Google Sheets (OAuth2) credential to all Sheets nodes; replace
PASTE_SHEET_ID. - SMTP credential; set sender and recipient in Send Review Email.
- Test run: one page with
active=TRUE, execute manually, then enable the schedule. - Optional: point POST FAQs to CMS at your CMS webhook.
Customization: model IDs sit in Build Extractor Request, Build Planner Request and Gate B — any OpenRouter ID works. Cadence in the Schedule Trigger; category and intent vocabularies in the same code nodes.
~$0.0035 per page run across three models (gpt-4o-mini, claude-sonnet-4.5, gemini-2.5-flash). A catalogue of 50–100 pages on a weekly cadence is ~$0.75–1.50/month; a single page ~$0.015. Cost is not the argument here — the fact base and the review process weigh more than the API bill. (A model calculation, not a measurement — see the write-up.)
CC BY 4.0. Use it, adapt it, pass it on — with attribution to Eugen Ullrich, eullrich.com.