About knock-in-app-ui
knock-in-app-ui is a skill for developers building Knock feeds and guides in apps, with detailed guidance for setting up, rendering, and debugging guides in React. It uses Knock CLI discovery for environment-specific values and does not extend its React instructions to other client SDKs.
Key features
- 01Choose between feeds and guides
- 02Set up React guide providers
- 03Render guides with hooks
- 04Type content from message schemas
- 05Debug with the toolbar and triage steps
Use cases
- 01Add guides to a React app for the first time
- 02Build a component from an existing guide
- 03Type guide content and track engagement
- 04Investigate why a guide is not rendering
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ knocklabs/ skills --skill knock-in-app-uiAfter installing, type/knock-in-app-uiin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
rules/debugging-guides.mdfeeds-vs-guides.mdrendering-guides-react.mdsetup-guide-providers-react.mdDetails
From the project READMEKnock in-app UI skill
This 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.
Reference: https://docs.knock.app/in-app-ui/overview
Overview
The skill is organized into four focused rule files. Client-framework guidance is scoped per framework via a -<framework> suffix (currently only React). Cross-framework concepts live in unsuffixed files.
- Feeds vs. guides (framework-agnostic) — which product to pick for a given surface and why
- Setting up the guide providers in React —
KnockProviderandKnockGuideProviderprops, where each value comes from, and how to sequence them - Rendering guides in React — building a guide component with
useGuide/useGuides, typed content, and engagement tracking - Debugging guides (framework-agnostic) — the guides toolbar, the triage checklist, and testing workflow
Framework scope: right now this skill only covers React (
@knocklabs/react). 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.
How to use this skill
When deciding what to build
Start with rules/feeds-vs-guides.md:
- Confirm the surface you're building is actually a guide, not a feed
- Check the decision table before picking a direction
- If the answer is "both," wrap the app in
KnockProvideronce and render each product's provider where it's needed
When adding guides to a React app for the first time
- Read
rules/setup-guide-providers-react.md - Before running environment-scoped CLI commands, confirm authentication and inspect the account's environments. First run
knock whoami— if it errors with something like "not authenticated" or "no user session," runknock loginand ask the user to complete the browser flow before continuing. Then runknock environment list. If it returns one environment, use that default (production on new accounts); if it returns multiple, ask the user to choose. Remember the slug as<env-slug>and pass--environment <env-slug>on every subsequent environment-scopedknockcommand. - Before asking the user anything about the channel, discover
channelIdvia the Knock CLI: runknock 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 getchannelId" procedure for the full fallback order. - Ask the user only for values that can't be auto-discovered — primarily the public
apiKeyfor the chosen environment (and confirmuser.idis coming from the app's auth context). Do not bundle theapiKeyask withchannelId. - Wire
KnockProvider+KnockGuideProviderat the top of the tree. - Gate
readyToTargeton any async data your targeting depends on. - Get a real guide rendering before stopping. Run
knock guide list --environment <env-slug> --json, show the user the options (key,name, each step'sschema_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 withknock message-type get <schema_key> --environment <env-slug> --jsonso 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 <env-slug>) using a built-in message type (card,banner, ormodal) with obvious-placeholder content — don't stall waiting for manual dashboard setup. Seerules/rendering-guides-react.md→ "First guide: discover real guides via CLI before writing code" for the full procedure including the empty-environment branch. - 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.
When building a new guide component in React
- Follow the workflow in
rules/rendering-guides-react.md - Discover the target guide (or message type) via the Knock CLI before picking values.
knock guide list --environment <env-slug> --jsonfor the guide'skey/ stepschema_key;knock message-type get <schema_key> --environment <env-slug> --jsonfor the content schema. Avoid placeholder strings. - Pick
useGuidefor single-guide surfaces,useGuidesfor lists - Define a TypeScript type that mirrors the message type schema you just pulled
- Wire
markAsSeen,markAsInteracted, andmarkAsArchived— custom components must do this themselves
When a guide isn't rendering
- Open
rules/debugging-guides.mdand work the triage checklist top to bottom - Turn on the guides toolbar (
?knock_guide_toolbar=true) first — it answers most questions in seconds - Distinguish server-side (targeting/eligibility) from client-side (provider/component) failures before digging deeper
Rule files reference
rules/feeds-vs-guides.md— product selection between feeds and guides (framework-agnostic)rules/setup-guide-providers-react.md— configuringKnockProviderandKnockGuideProviderfor guides (React)rules/rendering-guides-react.md—useGuide,useGuides, typed content, engagement tracking (React)rules/debugging-guides.md— toolbar, triage checklist, testing workflow (framework-agnostic)
Quick reference
The examples below are React. For any other client SDK, see the note at the top of Overview before proceeding.
Providers (minimum viable setup — React)
<KnockProvider
apiKey={process.env.NEXT_PUBLIC_KNOCK_API_KEY}
user={{ id: currentUser.id }}
>
<KnockGuideProvider
channelId={process.env.NEXT_PUBLIC_KNOCK_GUIDE_CHANNEL_ID}
readyToTarget
listenForUpdates
>
{children}
</KnockGuideProvider>
</KnockProvider>
Where to source each value
-
Auth first, then environment — Knock is environment-scoped. Before environment-scoped CLI commands, verify authentication with
knock whoami; if it errors, runknock loginand wait for the browser flow. Then runknock environment list. When a single environment is returned use it automatically, or ask the user to choose when several exist. Pass--environment <env-slug>on every subsequent environment-scoped command; otherwise the CLI uses the account's default environment. -
apiKey— Knock dashboard → Platform → API keys → publicpk_...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) -
user.id— your auth context; must match the id used when identifying the user from your backend -
channelId— the UUID of the guide channel, not its key. Channels are account-scoped, soknock channel listdoes not take--environment. Always attempt CLI discovery before asking the user:knock channel list --json | jq -r '.[] | select(.key == "knock-guide") | .id'If this prints a UUID, use it directly — don't prompt for confirmation. The default guide channel key is
knock-guide(typein_app_guide). Fall back to the dashboard (Settings → Integrations → Channels) only if the CLI returns nothing or errors. Seerules/setup-guide-providers-react.mdfor the full procedure.
Hooks at a glance
useGuide({ type })— one guide by message typeuseGuide({ key })— one specific guide by keyuseGuides({ type })— array of guides by message typeuseGuideContext()— low-level client access
Engagement methods
step.markAsSeen()— impression (call fromuseEffectkeyed onstep)step.markAsInteracted()— primary actionstep.markAsArchived()— dismissal; removes the guide for this user going forward
First stop when something's wrong
Append ?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.
Best practices summary
- Pick the right product. Feeds for chronological lists, guides for targeted UI.
- Mount providers once, high in the tree. Inside your auth boundary, above any route that renders guides.
- Never pass a placeholder user. Wait for auth to resolve before mounting
KnockProvider. - Gate
readyToTargeton async data your targeting rules depend on. - Type your content.
useGuide<T>should mirror the Knock message type schema. - Always handle engagement. Custom components must call
markAsSeen,markAsInteracted, andmarkAsArchivedthemselves. - Use the toolbar first. Most "the guide isn't showing" questions are answered in seconds.