[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-knock-knock-in-app-ui":3,"mdc--bajets-key":35,"related-org-knock-knock-in-app-ui":1602,"related-repo-knock-knock-in-app-ui":1698},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":26,"topics":30,"repo":31,"sourceUrl":33,"mdContent":34},"knock-in-app-ui","implement Knock in-app UI in React","Guidance for implementing Knock in-app UI in a web app, with a focus on setting up, rendering, and debugging Knock guides in React.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"knock","Knock","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fknock.png","knocklabs",[13,17,20,23],{"name":14,"slug":15,"type":16},"React","react","tag",{"name":18,"slug":19,"type":16},"Messaging","messaging",{"name":21,"slug":22,"type":16},"UI Components","ui-components",{"name":24,"slug":25,"type":16},"Frontend","frontend",0,"https:\u002F\u002Fgithub.com\u002Fknocklabs\u002Fskills","2026-07-14T05:23:53.566839",null,[],{"repoUrl":27,"stars":26,"forks":26,"topics":32,"description":29},[],"https:\u002F\u002Fgithub.com\u002Fknocklabs\u002Fskills\u002Ftree\u002FHEAD\u002Fskills\u002Fknock-in-app-ui","---\nname: knock-in-app-ui\ndescription: Guidance for implementing Knock in-app UI in a web app, with a focus on setting up, rendering, and debugging Knock guides in React.\n---\n\n# Knock in-app UI skill\n\nThis skill helps you build in-app UI with Knock. It covers the two in-app products — **feeds** and **guides** — at a high level, then goes deep on guides: provider setup, rendering with hooks, and debugging.\n\nReference: https:\u002F\u002Fdocs.knock.app\u002Fin-app-ui\u002Foverview\n\n## Overview\n\nThe skill is organized into four focused rule files. Client-framework guidance is scoped per framework via a `-\u003Cframework>` suffix (currently only React). Cross-framework concepts live in unsuffixed files.\n\n1. **Feeds vs. guides** (framework-agnostic) — which product to pick for a given surface and why\n2. **Setting up the guide providers in React** — `KnockProvider` and `KnockGuideProvider` props, where each value comes from, and how to sequence them\n3. **Rendering guides in React** — building a guide component with `useGuide` \u002F `useGuides`, typed content, and engagement tracking\n4. **Debugging guides** (framework-agnostic) — the guides toolbar, the triage checklist, and testing workflow\n\n> **Framework scope:** right now this skill only covers React (`@knocklabs\u002Freact`). If the user is building with Vue, Svelte, plain JS, React Native, iOS, or Android, stop and ask how they'd like to proceed — do not adapt the React rules to another client SDK on your own.\n\n## How to use this skill\n\n### When deciding what to build\n\nStart with `rules\u002Ffeeds-vs-guides.md`:\n\n- Confirm the surface you're building is actually a guide, not a feed\n- Check the decision table before picking a direction\n- If the answer is \"both,\" wrap the app in `KnockProvider` once and render each product's provider where it's needed\n\n### When adding guides to a React app for the first time\n\n1. Read `rules\u002Fsetup-guide-providers-react.md`\n2. **Before running any CLI commands, confirm the CLI is authenticated and which Knock environment this setup is for.** First run `knock whoami` — if it errors with something like \"not authenticated\" or \"no user session,\" run `knock login` and ask the user to complete the browser flow before continuing (the CLI persists the session so this is a one-time step per machine). Only after `knock whoami` succeeds, run `knock environment list` and ask the user to pick (the CLI defaults to `development`, but most real integrations target `production`). Remember that slug as `\u003Cenv-slug>` and pass `--environment \u003Cenv-slug>` on every subsequent environment-scoped `knock` command.\n3. **Before asking the user anything about the channel, discover `channelId` via the Knock CLI:** run `knock channel list --json | jq -r '.[] | select(.key == \"knock-guide\") | .id'`. Channels are account-scoped, so this command does **not** take `--environment`. If it prints a UUID, use it — do not ask the user to confirm or re-paste. Only ask the user if the CLI returns nothing or errors. See the rule file's \"Where to get `channelId`\" procedure for the full fallback order.\n4. Ask the user only for values that can't be auto-discovered — primarily the public `apiKey` for the chosen environment (and confirm `user.id` is coming from the app's auth context). Do not bundle the `apiKey` ask with `channelId`.\n5. Wire `KnockProvider` + `KnockGuideProvider` at the top of the tree.\n6. Gate `readyToTarget` on any async data your targeting depends on.\n7. **Get a real guide rendering before stopping.** Run `knock guide list --environment \u003Cenv-slug> --json`, show the user the options (`key`, `name`, each step's `schema_key`), and build the first component against a real guide's actual values. Do not scaffold with placeholder strings like `\"changelog-card\"`. Fetch the message type schema with `knock message-type get \u003Cschema_key> --environment \u003Cenv-slug> --json` so the content is typed. **If the environment has no guides, offer to scaffold a test one via the Knock CLI** (`knock guide new` → edit the JSON → `knock guide push --environment \u003Cenv-slug>`) using a built-in message type (`card`, `banner`, or `modal`) with obvious-placeholder content — don't stall waiting for manual dashboard setup. See `rules\u002Frendering-guides-react.md` → \"First guide: discover real guides via CLI before writing code\" for the full procedure including the empty-environment branch.\n8. Flag anything that still needs the user (paste `pk_` key, flip the guide to active in the dashboard, restart dev server) explicitly — don't leave them to discover it by absence.\n\n### When building a new guide component in React\n\n1. Follow the workflow in `rules\u002Frendering-guides-react.md`\n2. **Discover the target guide (or message type) via the Knock CLI before picking values.** `knock guide list --environment \u003Cenv-slug> --json` for the guide's `key` \u002F step `schema_key`; `knock message-type get \u003Cschema_key> --environment \u003Cenv-slug> --json` for the content schema. Avoid placeholder strings.\n3. Pick `useGuide` for single-guide surfaces, `useGuides` for lists\n4. Define a TypeScript type that mirrors the message type schema you just pulled\n5. Wire `markAsSeen`, `markAsInteracted`, and `markAsArchived` — custom components must do this themselves\n\n### When a guide isn't rendering\n\n1. Open `rules\u002Fdebugging-guides.md` and work the triage checklist top to bottom\n2. Turn on the guides toolbar (`?knock_guide_toolbar=true`) first — it answers most questions in seconds\n3. Distinguish server-side (targeting\u002Feligibility) from client-side (provider\u002Fcomponent) failures before digging deeper\n\n## Rule files reference\n\n- `rules\u002Ffeeds-vs-guides.md` — product selection between feeds and guides (framework-agnostic)\n- `rules\u002Fsetup-guide-providers-react.md` — configuring `KnockProvider` and `KnockGuideProvider` for guides (React)\n- `rules\u002Frendering-guides-react.md` — `useGuide`, `useGuides`, typed content, engagement tracking (React)\n- `rules\u002Fdebugging-guides.md` — toolbar, triage checklist, testing workflow (framework-agnostic)\n\n## Quick reference\n\nThe examples below are React. For any other client SDK, see the note at the top of **Overview** before proceeding.\n\n### Providers (minimum viable setup — React)\n\n```tsx\n\u003CKnockProvider\n  apiKey={process.env.NEXT_PUBLIC_KNOCK_API_KEY}\n  user={{ id: currentUser.id }}\n>\n  \u003CKnockGuideProvider\n    channelId={process.env.NEXT_PUBLIC_KNOCK_GUIDE_CHANNEL_ID}\n    readyToTarget\n    listenForUpdates\n  >\n    {children}\n  \u003C\u002FKnockGuideProvider>\n\u003C\u002FKnockProvider>\n```\n\n### Where to source each value\n\n- **Auth first, then environment** — Knock is environment-scoped. Before any CLI command, verify the CLI is authenticated with `knock whoami`; if it errors, run `knock login` and wait for the user to complete the browser flow. Then run `knock environment list` and confirm the target slug (`production`, `development`, …) with the user. Pass `--environment \u003Cenv-slug>` on every subsequent environment-scoped `knock` command. Don't rely on the CLI's `development` default.\n- `apiKey` — Knock dashboard → **Platform → API keys** → public `pk_...` key **from the tab for the chosen environment** (switch envs via the dashboard's environment selector first; remind the user to copy the key for the right env)\n- `user.id` — your auth context; must match the id used when identifying the user from your backend\n- `channelId` — the **UUID** of the guide channel, not its key. Channels are account-scoped, so `knock channel list` does **not** take `--environment`. **Always attempt CLI discovery before asking the user:**\n\n  ```bash\n  knock channel list --json | jq -r '.[] | select(.key == \"knock-guide\") | .id'\n  ```\n\n  If this prints a UUID, use it directly — don't prompt for confirmation. The default guide channel key is `knock-guide` (type `in_app_guide`). Fall back to the dashboard (**Settings → Integrations → Channels**) only if the CLI returns nothing or errors. See `rules\u002Fsetup-guide-providers-react.md` for the full procedure.\n\n### Hooks at a glance\n\n- `useGuide({ type })` — one guide by message type\n- `useGuide({ key })` — one specific guide by key\n- `useGuides({ type })` — array of guides by message type\n- `useGuideContext()` — low-level client access\n\n### Engagement methods\n\n- `step.markAsSeen()` — impression (call from `useEffect` keyed on `step`)\n- `step.markAsInteracted()` — primary action\n- `step.markAsArchived()` — dismissal; removes the guide for this user going forward\n\n### First stop when something's wrong\n\nAppend `?knock_guide_toolbar=true` to any URL. The toolbar shows all guides, which are active, which this user is eligible for, and why the rest were filtered out.\n\n## Best practices summary\n\n1. **Pick the right product.** Feeds for chronological lists, guides for targeted UI.\n2. **Mount providers once, high in the tree.** Inside your auth boundary, above any route that renders guides.\n3. **Never pass a placeholder user.** Wait for auth to resolve before mounting `KnockProvider`.\n4. **Gate `readyToTarget` on async data** your targeting rules depend on.\n5. **Type your content.** `useGuide\u003CT>` should mirror the Knock message type schema.\n6. **Always handle engagement.** Custom components must call `markAsSeen`, `markAsInteracted`, and `markAsArchived` themselves.\n7. **Use the toolbar first.** Most \"the guide isn't showing\" questions are answered in seconds.\n",{"data":36,"body":37},{"name":4,"description":6},{"type":38,"children":39},"root",[40,49,70,83,90,104,180,202,208,215,228,254,260,594,600,702,708,742,748,816,822,833,839,1095,1101,1350,1356,1403,1409,1461,1467,1479,1485,1596],{"type":41,"tag":42,"props":43,"children":45},"element","h1",{"id":44},"knock-in-app-ui-skill",[46],{"type":47,"value":48},"text","Knock in-app UI skill",{"type":41,"tag":50,"props":51,"children":52},"p",{},[53,55,61,63,68],{"type":47,"value":54},"This skill helps you build in-app UI with Knock. It covers the two in-app products — ",{"type":41,"tag":56,"props":57,"children":58},"strong",{},[59],{"type":47,"value":60},"feeds",{"type":47,"value":62}," and ",{"type":41,"tag":56,"props":64,"children":65},{},[66],{"type":47,"value":67},"guides",{"type":47,"value":69}," — at a high level, then goes deep on guides: provider setup, rendering with hooks, and debugging.",{"type":41,"tag":50,"props":71,"children":72},{},[73,75],{"type":47,"value":74},"Reference: ",{"type":41,"tag":76,"props":77,"children":81},"a",{"href":78,"rel":79},"https:\u002F\u002Fdocs.knock.app\u002Fin-app-ui\u002Foverview",[80],"nofollow",[82],{"type":47,"value":78},{"type":41,"tag":84,"props":85,"children":87},"h2",{"id":86},"overview",[88],{"type":47,"value":89},"Overview",{"type":41,"tag":50,"props":91,"children":92},{},[93,95,102],{"type":47,"value":94},"The skill is organized into four focused rule files. Client-framework guidance is scoped per framework via a ",{"type":41,"tag":96,"props":97,"children":99},"code",{"className":98},[],[100],{"type":47,"value":101},"-\u003Cframework>",{"type":47,"value":103}," suffix (currently only React). Cross-framework concepts live in unsuffixed files.",{"type":41,"tag":105,"props":106,"children":107},"ol",{},[108,119,144,170],{"type":41,"tag":109,"props":110,"children":111},"li",{},[112,117],{"type":41,"tag":56,"props":113,"children":114},{},[115],{"type":47,"value":116},"Feeds vs. guides",{"type":47,"value":118}," (framework-agnostic) — which product to pick for a given surface and why",{"type":41,"tag":109,"props":120,"children":121},{},[122,127,129,135,136,142],{"type":41,"tag":56,"props":123,"children":124},{},[125],{"type":47,"value":126},"Setting up the guide providers in React",{"type":47,"value":128}," — ",{"type":41,"tag":96,"props":130,"children":132},{"className":131},[],[133],{"type":47,"value":134},"KnockProvider",{"type":47,"value":62},{"type":41,"tag":96,"props":137,"children":139},{"className":138},[],[140],{"type":47,"value":141},"KnockGuideProvider",{"type":47,"value":143}," props, where each value comes from, and how to sequence them",{"type":41,"tag":109,"props":145,"children":146},{},[147,152,154,160,162,168],{"type":41,"tag":56,"props":148,"children":149},{},[150],{"type":47,"value":151},"Rendering guides in React",{"type":47,"value":153}," — building a guide component with ",{"type":41,"tag":96,"props":155,"children":157},{"className":156},[],[158],{"type":47,"value":159},"useGuide",{"type":47,"value":161}," \u002F ",{"type":41,"tag":96,"props":163,"children":165},{"className":164},[],[166],{"type":47,"value":167},"useGuides",{"type":47,"value":169},", typed content, and engagement tracking",{"type":41,"tag":109,"props":171,"children":172},{},[173,178],{"type":41,"tag":56,"props":174,"children":175},{},[176],{"type":47,"value":177},"Debugging guides",{"type":47,"value":179}," (framework-agnostic) — the guides toolbar, the triage checklist, and testing workflow",{"type":41,"tag":181,"props":182,"children":183},"blockquote",{},[184],{"type":41,"tag":50,"props":185,"children":186},{},[187,192,194,200],{"type":41,"tag":56,"props":188,"children":189},{},[190],{"type":47,"value":191},"Framework scope:",{"type":47,"value":193}," right now this skill only covers React (",{"type":41,"tag":96,"props":195,"children":197},{"className":196},[],[198],{"type":47,"value":199},"@knocklabs\u002Freact",{"type":47,"value":201},"). If the user is building with Vue, Svelte, plain JS, React Native, iOS, or Android, stop and ask how they'd like to proceed — do not adapt the React rules to another client SDK on your own.",{"type":41,"tag":84,"props":203,"children":205},{"id":204},"how-to-use-this-skill",[206],{"type":47,"value":207},"How to use this skill",{"type":41,"tag":209,"props":210,"children":212},"h3",{"id":211},"when-deciding-what-to-build",[213],{"type":47,"value":214},"When deciding what to build",{"type":41,"tag":50,"props":216,"children":217},{},[218,220,226],{"type":47,"value":219},"Start with ",{"type":41,"tag":96,"props":221,"children":223},{"className":222},[],[224],{"type":47,"value":225},"rules\u002Ffeeds-vs-guides.md",{"type":47,"value":227},":",{"type":41,"tag":229,"props":230,"children":231},"ul",{},[232,237,242],{"type":41,"tag":109,"props":233,"children":234},{},[235],{"type":47,"value":236},"Confirm the surface you're building is actually a guide, not a feed",{"type":41,"tag":109,"props":238,"children":239},{},[240],{"type":47,"value":241},"Check the decision table before picking a direction",{"type":41,"tag":109,"props":243,"children":244},{},[245,247,252],{"type":47,"value":246},"If the answer is \"both,\" wrap the app in ",{"type":41,"tag":96,"props":248,"children":250},{"className":249},[],[251],{"type":47,"value":134},{"type":47,"value":253}," once and render each product's provider where it's needed",{"type":41,"tag":209,"props":255,"children":257},{"id":256},"when-adding-guides-to-a-react-app-for-the-first-time",[258],{"type":47,"value":259},"When adding guides to a React app for the first time",{"type":41,"tag":105,"props":261,"children":262},{},[263,274,354,402,437,456,469,581],{"type":41,"tag":109,"props":264,"children":265},{},[266,268],{"type":47,"value":267},"Read ",{"type":41,"tag":96,"props":269,"children":271},{"className":270},[],[272],{"type":47,"value":273},"rules\u002Fsetup-guide-providers-react.md",{"type":41,"tag":109,"props":275,"children":276},{},[277,282,284,290,292,298,300,305,307,313,315,321,323,329,331,337,339,345,347,352],{"type":41,"tag":56,"props":278,"children":279},{},[280],{"type":47,"value":281},"Before running any CLI commands, confirm the CLI is authenticated and which Knock environment this setup is for.",{"type":47,"value":283}," First run ",{"type":41,"tag":96,"props":285,"children":287},{"className":286},[],[288],{"type":47,"value":289},"knock whoami",{"type":47,"value":291}," — if it errors with something like \"not authenticated\" or \"no user session,\" run ",{"type":41,"tag":96,"props":293,"children":295},{"className":294},[],[296],{"type":47,"value":297},"knock login",{"type":47,"value":299}," and ask the user to complete the browser flow before continuing (the CLI persists the session so this is a one-time step per machine). Only after ",{"type":41,"tag":96,"props":301,"children":303},{"className":302},[],[304],{"type":47,"value":289},{"type":47,"value":306}," succeeds, run ",{"type":41,"tag":96,"props":308,"children":310},{"className":309},[],[311],{"type":47,"value":312},"knock environment list",{"type":47,"value":314}," and ask the user to pick (the CLI defaults to ",{"type":41,"tag":96,"props":316,"children":318},{"className":317},[],[319],{"type":47,"value":320},"development",{"type":47,"value":322},", but most real integrations target ",{"type":41,"tag":96,"props":324,"children":326},{"className":325},[],[327],{"type":47,"value":328},"production",{"type":47,"value":330},"). Remember that slug as ",{"type":41,"tag":96,"props":332,"children":334},{"className":333},[],[335],{"type":47,"value":336},"\u003Cenv-slug>",{"type":47,"value":338}," and pass ",{"type":41,"tag":96,"props":340,"children":342},{"className":341},[],[343],{"type":47,"value":344},"--environment \u003Cenv-slug>",{"type":47,"value":346}," on every subsequent environment-scoped ",{"type":41,"tag":96,"props":348,"children":350},{"className":349},[],[351],{"type":47,"value":8},{"type":47,"value":353}," command.",{"type":41,"tag":109,"props":355,"children":356},{},[357,370,372,378,380,385,387,393,395,400],{"type":41,"tag":56,"props":358,"children":359},{},[360,362,368],{"type":47,"value":361},"Before asking the user anything about the channel, discover ",{"type":41,"tag":96,"props":363,"children":365},{"className":364},[],[366],{"type":47,"value":367},"channelId",{"type":47,"value":369}," via the Knock CLI:",{"type":47,"value":371}," run ",{"type":41,"tag":96,"props":373,"children":375},{"className":374},[],[376],{"type":47,"value":377},"knock channel list --json | jq -r '.[] | select(.key == \"knock-guide\") | .id'",{"type":47,"value":379},". Channels are account-scoped, so this command does ",{"type":41,"tag":56,"props":381,"children":382},{},[383],{"type":47,"value":384},"not",{"type":47,"value":386}," take ",{"type":41,"tag":96,"props":388,"children":390},{"className":389},[],[391],{"type":47,"value":392},"--environment",{"type":47,"value":394},". If it prints a UUID, use it — do not ask the user to confirm or re-paste. Only ask the user if the CLI returns nothing or errors. See the rule file's \"Where to get ",{"type":41,"tag":96,"props":396,"children":398},{"className":397},[],[399],{"type":47,"value":367},{"type":47,"value":401},"\" procedure for the full fallback order.",{"type":41,"tag":109,"props":403,"children":404},{},[405,407,413,415,421,423,428,430,435],{"type":47,"value":406},"Ask the user only for values that can't be auto-discovered — primarily the public ",{"type":41,"tag":96,"props":408,"children":410},{"className":409},[],[411],{"type":47,"value":412},"apiKey",{"type":47,"value":414}," for the chosen environment (and confirm ",{"type":41,"tag":96,"props":416,"children":418},{"className":417},[],[419],{"type":47,"value":420},"user.id",{"type":47,"value":422}," is coming from the app's auth context). Do not bundle the ",{"type":41,"tag":96,"props":424,"children":426},{"className":425},[],[427],{"type":47,"value":412},{"type":47,"value":429}," ask with ",{"type":41,"tag":96,"props":431,"children":433},{"className":432},[],[434],{"type":47,"value":367},{"type":47,"value":436},".",{"type":41,"tag":109,"props":438,"children":439},{},[440,442,447,449,454],{"type":47,"value":441},"Wire ",{"type":41,"tag":96,"props":443,"children":445},{"className":444},[],[446],{"type":47,"value":134},{"type":47,"value":448}," + ",{"type":41,"tag":96,"props":450,"children":452},{"className":451},[],[453],{"type":47,"value":141},{"type":47,"value":455}," at the top of the tree.",{"type":41,"tag":109,"props":457,"children":458},{},[459,461,467],{"type":47,"value":460},"Gate ",{"type":41,"tag":96,"props":462,"children":464},{"className":463},[],[465],{"type":47,"value":466},"readyToTarget",{"type":47,"value":468}," on any async data your targeting depends on.",{"type":41,"tag":109,"props":470,"children":471},{},[472,477,479,485,487,493,495,501,503,509,511,517,519,525,527,532,534,540,542,548,550,556,557,563,565,571,573,579],{"type":41,"tag":56,"props":473,"children":474},{},[475],{"type":47,"value":476},"Get a real guide rendering before stopping.",{"type":47,"value":478}," Run ",{"type":41,"tag":96,"props":480,"children":482},{"className":481},[],[483],{"type":47,"value":484},"knock guide list --environment \u003Cenv-slug> --json",{"type":47,"value":486},", show the user the options (",{"type":41,"tag":96,"props":488,"children":490},{"className":489},[],[491],{"type":47,"value":492},"key",{"type":47,"value":494},", ",{"type":41,"tag":96,"props":496,"children":498},{"className":497},[],[499],{"type":47,"value":500},"name",{"type":47,"value":502},", each step's ",{"type":41,"tag":96,"props":504,"children":506},{"className":505},[],[507],{"type":47,"value":508},"schema_key",{"type":47,"value":510},"), and build the first component against a real guide's actual values. Do not scaffold with placeholder strings like ",{"type":41,"tag":96,"props":512,"children":514},{"className":513},[],[515],{"type":47,"value":516},"\"changelog-card\"",{"type":47,"value":518},". Fetch the message type schema with ",{"type":41,"tag":96,"props":520,"children":522},{"className":521},[],[523],{"type":47,"value":524},"knock message-type get \u003Cschema_key> --environment \u003Cenv-slug> --json",{"type":47,"value":526}," so the content is typed. ",{"type":41,"tag":56,"props":528,"children":529},{},[530],{"type":47,"value":531},"If the environment has no guides, offer to scaffold a test one via the Knock CLI",{"type":47,"value":533}," (",{"type":41,"tag":96,"props":535,"children":537},{"className":536},[],[538],{"type":47,"value":539},"knock guide new",{"type":47,"value":541}," → edit the JSON → ",{"type":41,"tag":96,"props":543,"children":545},{"className":544},[],[546],{"type":47,"value":547},"knock guide push --environment \u003Cenv-slug>",{"type":47,"value":549},") using a built-in message type (",{"type":41,"tag":96,"props":551,"children":553},{"className":552},[],[554],{"type":47,"value":555},"card",{"type":47,"value":494},{"type":41,"tag":96,"props":558,"children":560},{"className":559},[],[561],{"type":47,"value":562},"banner",{"type":47,"value":564},", or ",{"type":41,"tag":96,"props":566,"children":568},{"className":567},[],[569],{"type":47,"value":570},"modal",{"type":47,"value":572},") with obvious-placeholder content — don't stall waiting for manual dashboard setup. See ",{"type":41,"tag":96,"props":574,"children":576},{"className":575},[],[577],{"type":47,"value":578},"rules\u002Frendering-guides-react.md",{"type":47,"value":580}," → \"First guide: discover real guides via CLI before writing code\" for the full procedure including the empty-environment branch.",{"type":41,"tag":109,"props":582,"children":583},{},[584,586,592],{"type":47,"value":585},"Flag anything that still needs the user (paste ",{"type":41,"tag":96,"props":587,"children":589},{"className":588},[],[590],{"type":47,"value":591},"pk_",{"type":47,"value":593}," key, flip the guide to active in the dashboard, restart dev server) explicitly — don't leave them to discover it by absence.",{"type":41,"tag":209,"props":595,"children":597},{"id":596},"when-building-a-new-guide-component-in-react",[598],{"type":47,"value":599},"When building a new guide component in React",{"type":41,"tag":105,"props":601,"children":602},{},[603,613,651,670,675],{"type":41,"tag":109,"props":604,"children":605},{},[606,608],{"type":47,"value":607},"Follow the workflow in ",{"type":41,"tag":96,"props":609,"children":611},{"className":610},[],[612],{"type":47,"value":578},{"type":41,"tag":109,"props":614,"children":615},{},[616,621,623,628,630,635,637,642,644,649],{"type":41,"tag":56,"props":617,"children":618},{},[619],{"type":47,"value":620},"Discover the target guide (or message type) via the Knock CLI before picking values.",{"type":47,"value":622}," ",{"type":41,"tag":96,"props":624,"children":626},{"className":625},[],[627],{"type":47,"value":484},{"type":47,"value":629}," for the guide's ",{"type":41,"tag":96,"props":631,"children":633},{"className":632},[],[634],{"type":47,"value":492},{"type":47,"value":636}," \u002F step ",{"type":41,"tag":96,"props":638,"children":640},{"className":639},[],[641],{"type":47,"value":508},{"type":47,"value":643},"; ",{"type":41,"tag":96,"props":645,"children":647},{"className":646},[],[648],{"type":47,"value":524},{"type":47,"value":650}," for the content schema. Avoid placeholder strings.",{"type":41,"tag":109,"props":652,"children":653},{},[654,656,661,663,668],{"type":47,"value":655},"Pick ",{"type":41,"tag":96,"props":657,"children":659},{"className":658},[],[660],{"type":47,"value":159},{"type":47,"value":662}," for single-guide surfaces, ",{"type":41,"tag":96,"props":664,"children":666},{"className":665},[],[667],{"type":47,"value":167},{"type":47,"value":669}," for lists",{"type":41,"tag":109,"props":671,"children":672},{},[673],{"type":47,"value":674},"Define a TypeScript type that mirrors the message type schema you just pulled",{"type":41,"tag":109,"props":676,"children":677},{},[678,679,685,686,692,694,700],{"type":47,"value":441},{"type":41,"tag":96,"props":680,"children":682},{"className":681},[],[683],{"type":47,"value":684},"markAsSeen",{"type":47,"value":494},{"type":41,"tag":96,"props":687,"children":689},{"className":688},[],[690],{"type":47,"value":691},"markAsInteracted",{"type":47,"value":693},", and ",{"type":41,"tag":96,"props":695,"children":697},{"className":696},[],[698],{"type":47,"value":699},"markAsArchived",{"type":47,"value":701}," — custom components must do this themselves",{"type":41,"tag":209,"props":703,"children":705},{"id":704},"when-a-guide-isnt-rendering",[706],{"type":47,"value":707},"When a guide isn't rendering",{"type":41,"tag":105,"props":709,"children":710},{},[711,724,737],{"type":41,"tag":109,"props":712,"children":713},{},[714,716,722],{"type":47,"value":715},"Open ",{"type":41,"tag":96,"props":717,"children":719},{"className":718},[],[720],{"type":47,"value":721},"rules\u002Fdebugging-guides.md",{"type":47,"value":723}," and work the triage checklist top to bottom",{"type":41,"tag":109,"props":725,"children":726},{},[727,729,735],{"type":47,"value":728},"Turn on the guides toolbar (",{"type":41,"tag":96,"props":730,"children":732},{"className":731},[],[733],{"type":47,"value":734},"?knock_guide_toolbar=true",{"type":47,"value":736},") first — it answers most questions in seconds",{"type":41,"tag":109,"props":738,"children":739},{},[740],{"type":47,"value":741},"Distinguish server-side (targeting\u002Feligibility) from client-side (provider\u002Fcomponent) failures before digging deeper",{"type":41,"tag":84,"props":743,"children":745},{"id":744},"rule-files-reference",[746],{"type":47,"value":747},"Rule files reference",{"type":41,"tag":229,"props":749,"children":750},{},[751,761,784,806],{"type":41,"tag":109,"props":752,"children":753},{},[754,759],{"type":41,"tag":96,"props":755,"children":757},{"className":756},[],[758],{"type":47,"value":225},{"type":47,"value":760}," — product selection between feeds and guides (framework-agnostic)",{"type":41,"tag":109,"props":762,"children":763},{},[764,769,771,776,777,782],{"type":41,"tag":96,"props":765,"children":767},{"className":766},[],[768],{"type":47,"value":273},{"type":47,"value":770}," — configuring ",{"type":41,"tag":96,"props":772,"children":774},{"className":773},[],[775],{"type":47,"value":134},{"type":47,"value":62},{"type":41,"tag":96,"props":778,"children":780},{"className":779},[],[781],{"type":47,"value":141},{"type":47,"value":783}," for guides (React)",{"type":41,"tag":109,"props":785,"children":786},{},[787,792,793,798,799,804],{"type":41,"tag":96,"props":788,"children":790},{"className":789},[],[791],{"type":47,"value":578},{"type":47,"value":128},{"type":41,"tag":96,"props":794,"children":796},{"className":795},[],[797],{"type":47,"value":159},{"type":47,"value":494},{"type":41,"tag":96,"props":800,"children":802},{"className":801},[],[803],{"type":47,"value":167},{"type":47,"value":805},", typed content, engagement tracking (React)",{"type":41,"tag":109,"props":807,"children":808},{},[809,814],{"type":41,"tag":96,"props":810,"children":812},{"className":811},[],[813],{"type":47,"value":721},{"type":47,"value":815}," — toolbar, triage checklist, testing workflow (framework-agnostic)",{"type":41,"tag":84,"props":817,"children":819},{"id":818},"quick-reference",[820],{"type":47,"value":821},"Quick reference",{"type":41,"tag":50,"props":823,"children":824},{},[825,827,831],{"type":47,"value":826},"The examples below are React. For any other client SDK, see the note at the top of ",{"type":41,"tag":56,"props":828,"children":829},{},[830],{"type":47,"value":89},{"type":47,"value":832}," before proceeding.",{"type":41,"tag":209,"props":834,"children":836},{"id":835},"providers-minimum-viable-setup-react",[837],{"type":47,"value":838},"Providers (minimum viable setup — React)",{"type":41,"tag":840,"props":841,"children":846},"pre",{"className":842,"code":843,"language":844,"meta":845,"style":845},"language-tsx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003CKnockProvider\n  apiKey={process.env.NEXT_PUBLIC_KNOCK_API_KEY}\n  user={{ id: currentUser.id }}\n>\n  \u003CKnockGuideProvider\n    channelId={process.env.NEXT_PUBLIC_KNOCK_GUIDE_CHANNEL_ID}\n    readyToTarget\n    listenForUpdates\n  >\n    {children}\n  \u003C\u002FKnockGuideProvider>\n\u003C\u002FKnockProvider>\n","tsx","",[847],{"type":41,"tag":96,"props":848,"children":849},{"__ignoreMap":845},[850,868,912,955,964,978,1016,1025,1034,1043,1061,1078],{"type":41,"tag":851,"props":852,"children":855},"span",{"class":853,"line":854},"line",1,[856,862],{"type":41,"tag":851,"props":857,"children":859},{"style":858},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[860],{"type":47,"value":861},"\u003C",{"type":41,"tag":851,"props":863,"children":865},{"style":864},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[866],{"type":47,"value":867},"KnockProvider\n",{"type":41,"tag":851,"props":869,"children":871},{"class":853,"line":870},2,[872,878,883,889,893,898,902,907],{"type":41,"tag":851,"props":873,"children":875},{"style":874},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[876],{"type":47,"value":877},"  apiKey",{"type":41,"tag":851,"props":879,"children":880},{"style":858},[881],{"type":47,"value":882},"={",{"type":41,"tag":851,"props":884,"children":886},{"style":885},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[887],{"type":47,"value":888},"process",{"type":41,"tag":851,"props":890,"children":891},{"style":858},[892],{"type":47,"value":436},{"type":41,"tag":851,"props":894,"children":895},{"style":885},[896],{"type":47,"value":897},"env",{"type":41,"tag":851,"props":899,"children":900},{"style":858},[901],{"type":47,"value":436},{"type":41,"tag":851,"props":903,"children":904},{"style":885},[905],{"type":47,"value":906},"NEXT_PUBLIC_KNOCK_API_KEY",{"type":41,"tag":851,"props":908,"children":909},{"style":858},[910],{"type":47,"value":911},"}\n",{"type":41,"tag":851,"props":913,"children":915},{"class":853,"line":914},3,[916,921,926,932,936,941,945,950],{"type":41,"tag":851,"props":917,"children":918},{"style":874},[919],{"type":47,"value":920},"  user",{"type":41,"tag":851,"props":922,"children":923},{"style":858},[924],{"type":47,"value":925},"={{",{"type":41,"tag":851,"props":927,"children":929},{"style":928},"--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178",[930],{"type":47,"value":931}," id",{"type":41,"tag":851,"props":933,"children":934},{"style":858},[935],{"type":47,"value":227},{"type":41,"tag":851,"props":937,"children":938},{"style":885},[939],{"type":47,"value":940}," currentUser",{"type":41,"tag":851,"props":942,"children":943},{"style":858},[944],{"type":47,"value":436},{"type":41,"tag":851,"props":946,"children":947},{"style":885},[948],{"type":47,"value":949},"id ",{"type":41,"tag":851,"props":951,"children":952},{"style":858},[953],{"type":47,"value":954},"}}\n",{"type":41,"tag":851,"props":956,"children":958},{"class":853,"line":957},4,[959],{"type":41,"tag":851,"props":960,"children":961},{"style":858},[962],{"type":47,"value":963},">\n",{"type":41,"tag":851,"props":965,"children":967},{"class":853,"line":966},5,[968,973],{"type":41,"tag":851,"props":969,"children":970},{"style":858},[971],{"type":47,"value":972},"  \u003C",{"type":41,"tag":851,"props":974,"children":975},{"style":864},[976],{"type":47,"value":977},"KnockGuideProvider\n",{"type":41,"tag":851,"props":979,"children":981},{"class":853,"line":980},6,[982,987,991,995,999,1003,1007,1012],{"type":41,"tag":851,"props":983,"children":984},{"style":874},[985],{"type":47,"value":986},"    channelId",{"type":41,"tag":851,"props":988,"children":989},{"style":858},[990],{"type":47,"value":882},{"type":41,"tag":851,"props":992,"children":993},{"style":885},[994],{"type":47,"value":888},{"type":41,"tag":851,"props":996,"children":997},{"style":858},[998],{"type":47,"value":436},{"type":41,"tag":851,"props":1000,"children":1001},{"style":885},[1002],{"type":47,"value":897},{"type":41,"tag":851,"props":1004,"children":1005},{"style":858},[1006],{"type":47,"value":436},{"type":41,"tag":851,"props":1008,"children":1009},{"style":885},[1010],{"type":47,"value":1011},"NEXT_PUBLIC_KNOCK_GUIDE_CHANNEL_ID",{"type":41,"tag":851,"props":1013,"children":1014},{"style":858},[1015],{"type":47,"value":911},{"type":41,"tag":851,"props":1017,"children":1019},{"class":853,"line":1018},7,[1020],{"type":41,"tag":851,"props":1021,"children":1022},{"style":874},[1023],{"type":47,"value":1024},"    readyToTarget\n",{"type":41,"tag":851,"props":1026,"children":1028},{"class":853,"line":1027},8,[1029],{"type":41,"tag":851,"props":1030,"children":1031},{"style":874},[1032],{"type":47,"value":1033},"    listenForUpdates\n",{"type":41,"tag":851,"props":1035,"children":1037},{"class":853,"line":1036},9,[1038],{"type":41,"tag":851,"props":1039,"children":1040},{"style":858},[1041],{"type":47,"value":1042},"  >\n",{"type":41,"tag":851,"props":1044,"children":1046},{"class":853,"line":1045},10,[1047,1052,1057],{"type":41,"tag":851,"props":1048,"children":1049},{"style":858},[1050],{"type":47,"value":1051},"    {",{"type":41,"tag":851,"props":1053,"children":1054},{"style":885},[1055],{"type":47,"value":1056},"children",{"type":41,"tag":851,"props":1058,"children":1059},{"style":858},[1060],{"type":47,"value":911},{"type":41,"tag":851,"props":1062,"children":1064},{"class":853,"line":1063},11,[1065,1070,1074],{"type":41,"tag":851,"props":1066,"children":1067},{"style":858},[1068],{"type":47,"value":1069},"  \u003C\u002F",{"type":41,"tag":851,"props":1071,"children":1072},{"style":864},[1073],{"type":47,"value":141},{"type":41,"tag":851,"props":1075,"children":1076},{"style":858},[1077],{"type":47,"value":963},{"type":41,"tag":851,"props":1079,"children":1081},{"class":853,"line":1080},12,[1082,1087,1091],{"type":41,"tag":851,"props":1083,"children":1084},{"style":858},[1085],{"type":47,"value":1086},"\u003C\u002F",{"type":41,"tag":851,"props":1088,"children":1089},{"style":864},[1090],{"type":47,"value":134},{"type":41,"tag":851,"props":1092,"children":1093},{"style":858},[1094],{"type":47,"value":963},{"type":41,"tag":209,"props":1096,"children":1098},{"id":1097},"where-to-source-each-value",[1099],{"type":47,"value":1100},"Where to source each value",{"type":41,"tag":229,"props":1102,"children":1103},{},[1104,1168,1200,1210],{"type":41,"tag":109,"props":1105,"children":1106},{},[1107,1112,1114,1119,1121,1126,1128,1133,1135,1140,1141,1146,1148,1153,1154,1159,1161,1166],{"type":41,"tag":56,"props":1108,"children":1109},{},[1110],{"type":47,"value":1111},"Auth first, then environment",{"type":47,"value":1113}," — Knock is environment-scoped. Before any CLI command, verify the CLI is authenticated with ",{"type":41,"tag":96,"props":1115,"children":1117},{"className":1116},[],[1118],{"type":47,"value":289},{"type":47,"value":1120},"; if it errors, run ",{"type":41,"tag":96,"props":1122,"children":1124},{"className":1123},[],[1125],{"type":47,"value":297},{"type":47,"value":1127}," and wait for the user to complete the browser flow. Then run ",{"type":41,"tag":96,"props":1129,"children":1131},{"className":1130},[],[1132],{"type":47,"value":312},{"type":47,"value":1134}," and confirm the target slug (",{"type":41,"tag":96,"props":1136,"children":1138},{"className":1137},[],[1139],{"type":47,"value":328},{"type":47,"value":494},{"type":41,"tag":96,"props":1142,"children":1144},{"className":1143},[],[1145],{"type":47,"value":320},{"type":47,"value":1147},", …) with the user. Pass ",{"type":41,"tag":96,"props":1149,"children":1151},{"className":1150},[],[1152],{"type":47,"value":344},{"type":47,"value":346},{"type":41,"tag":96,"props":1155,"children":1157},{"className":1156},[],[1158],{"type":47,"value":8},{"type":47,"value":1160}," command. Don't rely on the CLI's ",{"type":41,"tag":96,"props":1162,"children":1164},{"className":1163},[],[1165],{"type":47,"value":320},{"type":47,"value":1167}," default.",{"type":41,"tag":109,"props":1169,"children":1170},{},[1171,1176,1178,1183,1185,1191,1193,1198],{"type":41,"tag":96,"props":1172,"children":1174},{"className":1173},[],[1175],{"type":47,"value":412},{"type":47,"value":1177}," — Knock dashboard → ",{"type":41,"tag":56,"props":1179,"children":1180},{},[1181],{"type":47,"value":1182},"Platform → API keys",{"type":47,"value":1184}," → public ",{"type":41,"tag":96,"props":1186,"children":1188},{"className":1187},[],[1189],{"type":47,"value":1190},"pk_...",{"type":47,"value":1192}," key ",{"type":41,"tag":56,"props":1194,"children":1195},{},[1196],{"type":47,"value":1197},"from the tab for the chosen environment",{"type":47,"value":1199}," (switch envs via the dashboard's environment selector first; remind the user to copy the key for the right env)",{"type":41,"tag":109,"props":1201,"children":1202},{},[1203,1208],{"type":41,"tag":96,"props":1204,"children":1206},{"className":1205},[],[1207],{"type":47,"value":420},{"type":47,"value":1209}," — your auth context; must match the id used when identifying the user from your backend",{"type":41,"tag":109,"props":1211,"children":1212},{},[1213,1218,1220,1225,1227,1233,1235,1239,1240,1245,1247,1252,1314,1318,1320,1326,1328,1334,1336,1341,1343,1348],{"type":41,"tag":96,"props":1214,"children":1216},{"className":1215},[],[1217],{"type":47,"value":367},{"type":47,"value":1219}," — the ",{"type":41,"tag":56,"props":1221,"children":1222},{},[1223],{"type":47,"value":1224},"UUID",{"type":47,"value":1226}," of the guide channel, not its key. Channels are account-scoped, so ",{"type":41,"tag":96,"props":1228,"children":1230},{"className":1229},[],[1231],{"type":47,"value":1232},"knock channel list",{"type":47,"value":1234}," does ",{"type":41,"tag":56,"props":1236,"children":1237},{},[1238],{"type":47,"value":384},{"type":47,"value":386},{"type":41,"tag":96,"props":1241,"children":1243},{"className":1242},[],[1244],{"type":47,"value":392},{"type":47,"value":1246},". ",{"type":41,"tag":56,"props":1248,"children":1249},{},[1250],{"type":47,"value":1251},"Always attempt CLI discovery before asking the user:",{"type":41,"tag":840,"props":1253,"children":1257},{"className":1254,"code":1255,"language":1256,"meta":845,"style":845},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","knock channel list --json | jq -r '.[] | select(.key == \"knock-guide\") | .id'\n","bash",[1258],{"type":41,"tag":96,"props":1259,"children":1260},{"__ignoreMap":845},[1261],{"type":41,"tag":851,"props":1262,"children":1263},{"class":853,"line":854},[1264,1268,1274,1279,1284,1289,1294,1299,1304,1309],{"type":41,"tag":851,"props":1265,"children":1266},{"style":864},[1267],{"type":47,"value":8},{"type":41,"tag":851,"props":1269,"children":1271},{"style":1270},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[1272],{"type":47,"value":1273}," channel",{"type":41,"tag":851,"props":1275,"children":1276},{"style":1270},[1277],{"type":47,"value":1278}," list",{"type":41,"tag":851,"props":1280,"children":1281},{"style":1270},[1282],{"type":47,"value":1283}," --json",{"type":41,"tag":851,"props":1285,"children":1286},{"style":858},[1287],{"type":47,"value":1288}," |",{"type":41,"tag":851,"props":1290,"children":1291},{"style":864},[1292],{"type":47,"value":1293}," jq",{"type":41,"tag":851,"props":1295,"children":1296},{"style":1270},[1297],{"type":47,"value":1298}," -r",{"type":41,"tag":851,"props":1300,"children":1301},{"style":858},[1302],{"type":47,"value":1303}," '",{"type":41,"tag":851,"props":1305,"children":1306},{"style":1270},[1307],{"type":47,"value":1308},".[] | select(.key == \"knock-guide\") | .id",{"type":41,"tag":851,"props":1310,"children":1311},{"style":858},[1312],{"type":47,"value":1313},"'\n",{"type":41,"tag":1315,"props":1316,"children":1317},"br",{},[],{"type":47,"value":1319},"If this prints a UUID, use it directly — don't prompt for confirmation. The default guide channel key is ",{"type":41,"tag":96,"props":1321,"children":1323},{"className":1322},[],[1324],{"type":47,"value":1325},"knock-guide",{"type":47,"value":1327}," (type ",{"type":41,"tag":96,"props":1329,"children":1331},{"className":1330},[],[1332],{"type":47,"value":1333},"in_app_guide",{"type":47,"value":1335},"). Fall back to the dashboard (",{"type":41,"tag":56,"props":1337,"children":1338},{},[1339],{"type":47,"value":1340},"Settings → Integrations → Channels",{"type":47,"value":1342},") only if the CLI returns nothing or errors. See ",{"type":41,"tag":96,"props":1344,"children":1346},{"className":1345},[],[1347],{"type":47,"value":273},{"type":47,"value":1349}," for the full procedure.",{"type":41,"tag":209,"props":1351,"children":1353},{"id":1352},"hooks-at-a-glance",[1354],{"type":47,"value":1355},"Hooks at a glance",{"type":41,"tag":229,"props":1357,"children":1358},{},[1359,1370,1381,1392],{"type":41,"tag":109,"props":1360,"children":1361},{},[1362,1368],{"type":41,"tag":96,"props":1363,"children":1365},{"className":1364},[],[1366],{"type":47,"value":1367},"useGuide({ type })",{"type":47,"value":1369}," — one guide by message type",{"type":41,"tag":109,"props":1371,"children":1372},{},[1373,1379],{"type":41,"tag":96,"props":1374,"children":1376},{"className":1375},[],[1377],{"type":47,"value":1378},"useGuide({ key })",{"type":47,"value":1380}," — one specific guide by key",{"type":41,"tag":109,"props":1382,"children":1383},{},[1384,1390],{"type":41,"tag":96,"props":1385,"children":1387},{"className":1386},[],[1388],{"type":47,"value":1389},"useGuides({ type })",{"type":47,"value":1391}," — array of guides by message type",{"type":41,"tag":109,"props":1393,"children":1394},{},[1395,1401],{"type":41,"tag":96,"props":1396,"children":1398},{"className":1397},[],[1399],{"type":47,"value":1400},"useGuideContext()",{"type":47,"value":1402}," — low-level client access",{"type":41,"tag":209,"props":1404,"children":1406},{"id":1405},"engagement-methods",[1407],{"type":47,"value":1408},"Engagement methods",{"type":41,"tag":229,"props":1410,"children":1411},{},[1412,1439,1450],{"type":41,"tag":109,"props":1413,"children":1414},{},[1415,1421,1423,1429,1431,1437],{"type":41,"tag":96,"props":1416,"children":1418},{"className":1417},[],[1419],{"type":47,"value":1420},"step.markAsSeen()",{"type":47,"value":1422}," — impression (call from ",{"type":41,"tag":96,"props":1424,"children":1426},{"className":1425},[],[1427],{"type":47,"value":1428},"useEffect",{"type":47,"value":1430}," keyed on ",{"type":41,"tag":96,"props":1432,"children":1434},{"className":1433},[],[1435],{"type":47,"value":1436},"step",{"type":47,"value":1438},")",{"type":41,"tag":109,"props":1440,"children":1441},{},[1442,1448],{"type":41,"tag":96,"props":1443,"children":1445},{"className":1444},[],[1446],{"type":47,"value":1447},"step.markAsInteracted()",{"type":47,"value":1449}," — primary action",{"type":41,"tag":109,"props":1451,"children":1452},{},[1453,1459],{"type":41,"tag":96,"props":1454,"children":1456},{"className":1455},[],[1457],{"type":47,"value":1458},"step.markAsArchived()",{"type":47,"value":1460}," — dismissal; removes the guide for this user going forward",{"type":41,"tag":209,"props":1462,"children":1464},{"id":1463},"first-stop-when-somethings-wrong",[1465],{"type":47,"value":1466},"First stop when something's wrong",{"type":41,"tag":50,"props":1468,"children":1469},{},[1470,1472,1477],{"type":47,"value":1471},"Append ",{"type":41,"tag":96,"props":1473,"children":1475},{"className":1474},[],[1476],{"type":47,"value":734},{"type":47,"value":1478}," to any URL. The toolbar shows all guides, which are active, which this user is eligible for, and why the rest were filtered out.",{"type":41,"tag":84,"props":1480,"children":1482},{"id":1481},"best-practices-summary",[1483],{"type":47,"value":1484},"Best practices summary",{"type":41,"tag":105,"props":1486,"children":1487},{},[1488,1498,1508,1524,1540,1557,1586],{"type":41,"tag":109,"props":1489,"children":1490},{},[1491,1496],{"type":41,"tag":56,"props":1492,"children":1493},{},[1494],{"type":47,"value":1495},"Pick the right product.",{"type":47,"value":1497}," Feeds for chronological lists, guides for targeted UI.",{"type":41,"tag":109,"props":1499,"children":1500},{},[1501,1506],{"type":41,"tag":56,"props":1502,"children":1503},{},[1504],{"type":47,"value":1505},"Mount providers once, high in the tree.",{"type":47,"value":1507}," Inside your auth boundary, above any route that renders guides.",{"type":41,"tag":109,"props":1509,"children":1510},{},[1511,1516,1518,1523],{"type":41,"tag":56,"props":1512,"children":1513},{},[1514],{"type":47,"value":1515},"Never pass a placeholder user.",{"type":47,"value":1517}," Wait for auth to resolve before mounting ",{"type":41,"tag":96,"props":1519,"children":1521},{"className":1520},[],[1522],{"type":47,"value":134},{"type":47,"value":436},{"type":41,"tag":109,"props":1525,"children":1526},{},[1527,1538],{"type":41,"tag":56,"props":1528,"children":1529},{},[1530,1531,1536],{"type":47,"value":460},{"type":41,"tag":96,"props":1532,"children":1534},{"className":1533},[],[1535],{"type":47,"value":466},{"type":47,"value":1537}," on async data",{"type":47,"value":1539}," your targeting rules depend on.",{"type":41,"tag":109,"props":1541,"children":1542},{},[1543,1548,1549,1555],{"type":41,"tag":56,"props":1544,"children":1545},{},[1546],{"type":47,"value":1547},"Type your content.",{"type":47,"value":622},{"type":41,"tag":96,"props":1550,"children":1552},{"className":1551},[],[1553],{"type":47,"value":1554},"useGuide\u003CT>",{"type":47,"value":1556}," should mirror the Knock message type schema.",{"type":41,"tag":109,"props":1558,"children":1559},{},[1560,1565,1567,1572,1573,1578,1579,1584],{"type":41,"tag":56,"props":1561,"children":1562},{},[1563],{"type":47,"value":1564},"Always handle engagement.",{"type":47,"value":1566}," Custom components must call ",{"type":41,"tag":96,"props":1568,"children":1570},{"className":1569},[],[1571],{"type":47,"value":684},{"type":47,"value":494},{"type":41,"tag":96,"props":1574,"children":1576},{"className":1575},[],[1577],{"type":47,"value":691},{"type":47,"value":693},{"type":41,"tag":96,"props":1580,"children":1582},{"className":1581},[],[1583],{"type":47,"value":699},{"type":47,"value":1585}," themselves.",{"type":41,"tag":109,"props":1587,"children":1588},{},[1589,1594],{"type":41,"tag":56,"props":1590,"children":1591},{},[1592],{"type":47,"value":1593},"Use the toolbar first.",{"type":47,"value":1595}," Most \"the guide isn't showing\" questions are answered in seconds.",{"type":41,"tag":1597,"props":1598,"children":1599},"style",{},[1600],{"type":47,"value":1601},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1603,"total":1018},[1604,1618,1625,1642,1657,1671,1684],{"slug":1605,"name":1605,"fn":1606,"description":1607,"org":1608,"tags":1609,"stars":26,"repoUrl":27,"updatedAt":1617},"knock-cli","manage Knock notification resources via CLI","Guidelines for working with the Knock CLI to manage workflows, templates, and other notification resources in a Knock project.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1610,1613,1614],{"name":1611,"slug":1612,"type":16},"CLI","cli",{"name":18,"slug":19,"type":16},{"name":1615,"slug":1616,"type":16},"Notifications","notifications","2026-07-14T05:23:51.065051",{"slug":4,"name":4,"fn":5,"description":6,"org":1619,"tags":1620,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1621,1622,1623,1624],{"name":24,"slug":25,"type":16},{"name":18,"slug":19,"type":16},{"name":14,"slug":15,"type":16},{"name":21,"slug":22,"type":16},{"slug":1626,"name":1626,"fn":1627,"description":1628,"org":1629,"tags":1630,"stars":26,"repoUrl":27,"updatedAt":1641},"knock-lifecycle-opportunities","identify lifecycle messaging opportunities","Scan a product codebase for activation, engagement, and retention moments and recommend lifecycle messaging opportunities. Use when finding onboarding, churn, trial, or habit-forming notification candidates without creating Knock resources.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1631,1634,1637,1638],{"name":1632,"slug":1633,"type":16},"Engagement","engagement",{"name":1635,"slug":1636,"type":16},"Marketing","marketing",{"name":18,"slug":19,"type":16},{"name":1639,"slug":1640,"type":16},"Product Management","product-management","2026-07-27T06:28:50.28638",{"slug":1643,"name":1643,"fn":1644,"description":1645,"org":1646,"tags":1647,"stars":26,"repoUrl":27,"updatedAt":1656},"knock-migrate-to-knock","migrate messaging infrastructure to Knock","Investigate existing messaging infrastructure in a codebase and recommend how it maps to Knock. Use when migrating from Braze, Courier, Customer.io, Iterable, SendGrid, or custom notification code, or when planning a move to Knock.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1648,1651,1652,1655],{"name":1649,"slug":1650,"type":16},"Infrastructure","infrastructure",{"name":18,"slug":19,"type":16},{"name":1653,"slug":1654,"type":16},"Migration","migration",{"name":1615,"slug":1616,"type":16},"2026-07-27T06:28:49.594684",{"slug":1658,"name":1658,"fn":1659,"description":1660,"org":1661,"tags":1662,"stars":26,"repoUrl":27,"updatedAt":1670},"knock-notification-best-practices","design effective notification systems","Comprehensive guidelines for designing, writing, and implementing effective notification systems across email, push, SMS, in-app, and chat channels.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1663,1666,1669],{"name":1664,"slug":1665,"type":16},"Best Practices","best-practices",{"name":1667,"slug":1668,"type":16},"Communications","communications",{"name":18,"slug":19,"type":16},"2026-07-14T05:23:54.812153",{"slug":1672,"name":1672,"fn":1673,"description":1674,"org":1675,"tags":1676,"stars":26,"repoUrl":27,"updatedAt":1683},"knock-product-messaging-strategy","design cross-channel product messaging systems","Design a cross-channel product messaging system that drives activation, engagement, and retention while controlling fatigue. Use when planning lifecycle messaging, auditing notification strategy, prioritizing workflows, or turning product moments into Knock workflows, guides, preferences, and measurement.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1677,1678,1679,1680],{"name":1632,"slug":1633,"type":16},{"name":18,"slug":19,"type":16},{"name":1639,"slug":1640,"type":16},{"name":1681,"slug":1682,"type":16},"Strategy","strategy","2026-07-27T06:28:49.935507",{"slug":1685,"name":1685,"fn":1686,"description":1687,"org":1688,"tags":1689,"stars":26,"repoUrl":27,"updatedAt":1697},"knock-setup","integrate Knock notification workflows","Connect Knock to your coding agent, discover and build notification workflows, and recommend how to trigger them from your application.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1690,1693,1696],{"name":1691,"slug":1692,"type":16},"API Development","api-development",{"name":1694,"slug":1695,"type":16},"Automation","automation",{"name":18,"slug":19,"type":16},"2026-07-27T06:06:35.280117",{"items":1699,"total":1018},[1700,1706,1713,1720,1727,1733,1740],{"slug":1605,"name":1605,"fn":1606,"description":1607,"org":1701,"tags":1702,"stars":26,"repoUrl":27,"updatedAt":1617},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1703,1704,1705],{"name":1611,"slug":1612,"type":16},{"name":18,"slug":19,"type":16},{"name":1615,"slug":1616,"type":16},{"slug":4,"name":4,"fn":5,"description":6,"org":1707,"tags":1708,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1709,1710,1711,1712],{"name":24,"slug":25,"type":16},{"name":18,"slug":19,"type":16},{"name":14,"slug":15,"type":16},{"name":21,"slug":22,"type":16},{"slug":1626,"name":1626,"fn":1627,"description":1628,"org":1714,"tags":1715,"stars":26,"repoUrl":27,"updatedAt":1641},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1716,1717,1718,1719],{"name":1632,"slug":1633,"type":16},{"name":1635,"slug":1636,"type":16},{"name":18,"slug":19,"type":16},{"name":1639,"slug":1640,"type":16},{"slug":1643,"name":1643,"fn":1644,"description":1645,"org":1721,"tags":1722,"stars":26,"repoUrl":27,"updatedAt":1656},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1723,1724,1725,1726],{"name":1649,"slug":1650,"type":16},{"name":18,"slug":19,"type":16},{"name":1653,"slug":1654,"type":16},{"name":1615,"slug":1616,"type":16},{"slug":1658,"name":1658,"fn":1659,"description":1660,"org":1728,"tags":1729,"stars":26,"repoUrl":27,"updatedAt":1670},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1730,1731,1732],{"name":1664,"slug":1665,"type":16},{"name":1667,"slug":1668,"type":16},{"name":18,"slug":19,"type":16},{"slug":1672,"name":1672,"fn":1673,"description":1674,"org":1734,"tags":1735,"stars":26,"repoUrl":27,"updatedAt":1683},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1736,1737,1738,1739],{"name":1632,"slug":1633,"type":16},{"name":18,"slug":19,"type":16},{"name":1639,"slug":1640,"type":16},{"name":1681,"slug":1682,"type":16},{"slug":1685,"name":1685,"fn":1686,"description":1687,"org":1741,"tags":1742,"stars":26,"repoUrl":27,"updatedAt":1697},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1743,1744,1745],{"name":1691,"slug":1692,"type":16},{"name":1694,"slug":1695,"type":16},{"name":18,"slug":19,"type":16}]