Survey models
Every model can ask an optional follow-up question after the score.
Install
Paste this in the pages where the survey may appear:The widget draws inside a Shadow DOM: your app’s CSS does not affect the
survey, and the survey’s CSS does not leak into your app. It works under a
Content Security Policy without
'unsafe-inline' in style-src — allow only
https://usekeep.dev in script-src and connect-src.Methods
function
surveyId (or surveys: ["…", "…"]) — the surveys this page may show.
debug: true logs to the console why a survey did not appear.function
Who is using your app. Every field is optional:
userId, email,
companyId, customerId (the customer’s id in your billing, like Stripe’s
cus_… — it makes the match to the account exact), plan, createdAt
(ISO 8601, for “new users” targeting) and signature (see below).function
Show it now. Used by the Manual (SDK) trigger, and any time you want.
function
Fires the Custom event trigger:
Keep.track("checkout_completed") shows
the surveys set up for that event.function
Forgets the user. Call it on logout.
Triggers and audience
Triggers: right away, after N seconds, after N page views, manually viaKeep.show, or on a custom event via Keep.track.
Audience: everyone, identified users only, new users (signed up in the last N
days), specific plans, or specific companies. Plan and company are the values
your app passes to Keep.identify. The audience is evaluated on Keep’s server,
which answers only “show” or “don’t show” — the list of plans or companies
never reaches the browser.
After someone answers or closes the survey, it is not shown to them again for
the number of days you set (90 by default).
Verified identity
Anything the browser sends can be typed by anyone, so identity has two layers:- Unsigned: the answer is stored with what your app said and marked not verified in Keep.
- Signed: your server signs the user with the identity secret (Feedback → Settings). The answer arrives verified.
userId — or of the email
when there is no userId:
How an answer is linked to an account
Strongest first:- The
customerIdyour app passed, matched exactly to a customer in your billing. - The respondent’s email, matched exactly to the account’s email.
- The company domain of the respondent’s email, when exactly one account has it — and never a public mailbox like gmail.com.
React and Next.js
Inline surveys
With the Inline display, place where it should appear:What the widget receives and sends
- It receives only what it needs to draw the survey: texts, scale, look and trigger. Nothing about your accounts, revenue, risk or audience.
- It sends the score, the comment, the identity you passed, and the page path — without the query string, which is where tokens tend to live.
- It uses no cookies. It keeps in
localStorageonly that someone answered or closed, so it does not ask again too soon. - Any failure is silent: a paused or deleted survey, a network error — your page stays as it was.
- Survey texts are always rendered as text, never as HTML.
Endpoints
Used by the widget; you do not need to call them.
Limits: a whole score on the survey’s scale, a comment of up to 2,000
characters, and 10 answers per hour per survey per address. With Allowed
sites set in Feedback → Settings, requests from other origins are refused.
Pausing a survey takes up to a minute to reach every page, because the
configuration is cached briefly.
Testing locally
UseKeep.init({ surveyId, debug: true }). The builder’s preview in Keep uses
this exact widget and never sends answers.