Skip to content

Add Configure to onboarding

This is the Quickstart for a surface that is not a chat: an onboarding step, a settings row, a first-run screen. Everything else on the Quickstart still applies, the credentials, the daily refresh, the commit, and the tools; only the entry point and the return change, and this page is those two things.

Two names below come from the Quickstart, and they are yours:

ts
import { Configure } from "configure";

export const configure = new Configure({ apiKey: process.env.CONFIGURE_API_KEY, agent: process.env.CONFIGURE_AGENT });
export const profileFor = (userId: string) => configure.profile({ externalId: userId });   // one handle per user, keyed by your id

// The daily read, also run once on the return. Returns null until the user has connected.
export async function refreshContext(userId: string) {
  const read = await profileFor(userId).read({ sections: ["identity", "preferences", "summary", "integrations"] });
  if (!read.profile.linked) return null;
  const text = read.profile.format();
  await store(userId, text);   // `store` is your database: one string per user
  return text;
}

Onboarding is not a chat, so there is no fixed message and no card. The entry point is your own button with its own label, and the click goes to a route on your server that sends the user to Configure's page. Pass returnUrl on the mint and Configure brings them back there when they finish, connected. Your return route refreshes their context (Quickstart, step 5) and moves on to the next screen, which can now be filled in from their profile instead of asked.

ts
const RETURN_URL = "https://yourapp.com/onboarding/return";   // a constant, never from the request

// The onboarding step's button goes here.
app.get("/onboarding/connect", async (req, res) => {
  const connect = await profileFor(req.user.id).connect({ returnUrl: RETURN_URL });
  res.redirect(connect.connect_url);   // Configure's page, then back; a user who already connected lands straight back
});

// Configure sends the user here when they are done.
app.get("/onboarding/return", async (req, res) => {
  const context = await refreshContext(req.user.id);   // reads the profile; null until linked
  if (!context) return res.redirect("/onboarding?step=2&notice=not-connected");
  res.redirect("/onboarding?step=3");
});

Two rules for the return:

  • returnUrl must be https (or http on localhost while you develop), and it is a constant, never built from the request. Configure forwards the user there without a click when the browser's Referer origin matches it, which the default policy sends, or when its host is in allowed_return_hosts on your developer account. Any other destination gets a button with the host spelled out, so a Configure page never sends someone onward silently. That list is not the same thing as npx configure add origin, which registers an OAuth callback and has no effect here.
  • Trust the profile, not the URL. The return route reads read().profile.linked and decides from that; anyone can type the return address into a browser.

An onboarding screen titled Connect your context, with a chip reading Connect followed by the four provider marks

The onboarding step. One chip, and the user leaves for Configure's page.

An onboarding screen titled Here's what Remy already knows, showing Nova's name, role, and location, a line reading Filled in from your Configure profile, connected apps, and how Remy will work with her

Back from Configure, the next step is already filled in, with one line saying where it came from and everything still editable.

What you can pre-fill, from read({ sections: ["identity", "summary", "integrations"] }):

FieldWhere it comes from
identity.given_name, identity.family_name, identity.emailThe account the user signed in with. identity.email_verified says whether Configure verified it.
identity.role, identity.occupation, identity.location, identity.company_websiteDerived from the user's memories. A thin profile leaves them null, so treat each as a default, not a fact.
integrations.gmail.connected, and the same for calendar, drive, notion, sheetsWhich apps the user connected. Show the connected ones as already on.
summaryOne paragraph on who the user is and how they like to work.

Anything still null after the return is a question for the next screen, not a blocker. A user who skips this step is not lost: the chip in your chat (Quickstart, step 2) offers the same trip later, and the card takes it from there.

A screen titled Remy is ready, Nova, with Remy's first message naming her work, her connected Gmail, and asking what to read first

The screen after onboarding. The first message is specific because the context stored on the return is injected on the first turn ([Quickstart, step 5](/quickstart#5-keep-their-context-current)).

An app that uses Configure only in onboarding still runs step 5: the profile keeps growing everywhere else the user takes it, and a snapshot from sign-up day goes stale.

Next

  • The chat surface, the card, and the rest of the loop: Quickstart.
  • The button for this step, and the connected state: Components.

Personalization infrastructure for agents