Quick Start
This path integrates Configure into an existing web agent. It does not scaffold a new app.
If your product runs on Photon/Spectrum, flip the Configure toggle instead: zero code, and you can adopt the SDK later with no migration. If your agent already speaks MCP, connect it to Configure MCP (remote clients paste https://mcp.configure.dev; code uses https://mcp.configure.dev/mcp). Continue below when you own the app UI, auth flow, and model loop.
For products with sign-in, start with Continue with Configure + inline Configure in chat. Use Link-only when your product has no sign-in flow or no place for an SSO button.
1. Install and run setup
bash
npm install configure
npx configure setup --usersIf you run npx configure setup without flags, choose For my users.
When setup opens the browser, complete Configure developer auth. Create or sign into a developer account, then choose the existing agent handle for the product you already ship or create one if this is a new agent. Creating the API key is a credential step, not a decision to build a new app. Setup writes:
bash
CONFIGURE_API_KEY=sk_...
CONFIGURE_PUBLISHABLE_KEY=pk_...
CONFIGURE_AGENT=your-agentIf .env already has these three values, reuse them and skip setup.
2. Add Continue with Configure
Add Configure beside the app's existing sign-in providers:
html
<script src="https://configure.dev/js/configure.js"></script>
<configure-sso-button
client-id="oc_..."
redirect-uri="https://app.example.com/auth/configure/callback"
scopes="profile.read profile.search profile.remember profile.commit"
width="100%">
</configure-sso-button>Create the OAuth client and implement the callback with the Continue with Configure guide. The callback must exchange the code on your backend and store Configure access and refresh tokens server-side:
ts
app.post("/api/configure/oauth/callback", async (req, res) => {
const { code, codeVerifier, redirectUri } = req.body;
const tokenRes = await fetch("https://api.configure.dev/oauth/token", {
method: "POST",
headers: {
"Authorization": "Basic " + Buffer.from(
process.env.CONFIGURE_OAUTH_CLIENT_ID + ":" +
process.env.CONFIGURE_OAUTH_CLIENT_SECRET
).toString("base64"),
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: redirectUri,
client_id: process.env.CONFIGURE_OAUTH_CLIENT_ID!,
code_verifier: codeVerifier,
resource: "https://api.configure.dev",
}),
});
const tokens = await tokenRes.json();
if (!tokenRes.ok) {
res.status(400).json({ error: "configure_oauth_failed" });
return;
}
req.session.configureAccessToken = tokens.access_token;
req.session.configureRefreshToken = tokens.refresh_token;
res.json({ connected: true });
});Never expose client_secret, sk_ keys, OAuth access tokens, or OAuth refresh tokens in browser JavaScript.
3. Add Configure to chat
Put Configure in the chat UI, either in the same + menu as Images and Files or in an integrations list. For users who completed Continue with Configure, this should open profile permissions, connected tools, and personalization settings instead of asking them to authenticate again.
html
<script src="https://configure.dev/js/configure.js"></script>
<div id="configure-entry"></div>
<script>
Configure.personalizationButton({
el: "#configure-entry",
publishableKey: "pk_...",
agent: "your-agent",
agentName: "Your Agent",
personalizationLabel: "Manage Configure",
variant: "integration",
onEvent(event) {
if (event.type === "configure:linked") {
fetch("/api/configure/session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
token: event.payload.token,
userId: event.payload.userId,
}),
});
}
},
});
</script>For SSO-authenticated users, keep OAuth tokens on the backend and let hosted Configure UI reuse the Configure-origin session. Pass a browser-safe Configure handoff token or userId only when your backend intentionally returns one for hosted UI. Do not pass OAuth access or refresh tokens into the browser.
If your product is not a chat UI, use a settings-page Link trigger instead. See Inline UI Components.
4. Store Link fallback tokens
The inline UI emits configure:linked when the user completes Configure Link. This is the fallback path for products without SSO and a repair path for users who need to re-link. Send the returned token to your backend and store it in the existing app session.
ts
app.post("/api/configure/session", requireUser, (req, res) => {
const { token, userId } = req.body;
if (!token) {
res.status(400).json({ error: "missing_token" });
return;
}
req.session.configureToken = token;
req.session.configureUserId = userId;
res.sendStatus(204);
});The token is an agent-scoped Configure token. Do not put it in the model prompt.
5. Wire Configure into your chat route
ts
import { Configure } from "configure";
const configure = new Configure({
apiKey: process.env.CONFIGURE_API_KEY,
agent: process.env.CONFIGURE_AGENT,
});
app.post("/api/chat", async (req, res) => {
const { messages } = req.body;
const token = req.session.configureAccessToken || req.session.configureToken;
if (!token) {
res.status(401).json({ error: "configure_not_connected" });
return;
}
const profile = configure.profile({ token });
// Expose Configure tools alongside your own. profile.tools() returns
// Anthropic-native { name, description, input_schema }: pass it straight to the
// Anthropic SDK, or wrap with toOpenAIFunctions() (exported from "configure") for OpenAI.
const tools = [
...yourTools,
...profile.tools({
connectors: ["gmail", "calendar"],
}),
];
// In your existing tool dispatch, route Configure-prefixed calls to Configure.
// executeTool accepts { name, arguments } (OpenAI) or { name, input } (Anthropic).
const dispatch = (toolCall) =>
toolCall.name.startsWith("configure_")
? profile.executeTool(toolCall)
: executeYourTool(toolCall);
// Run your existing provider loop with these tools + dispatch. A successful
// configure_profile_read call is the clearest smoke test for your tool router.
// Concrete OpenAI and Anthropic loops: /guides/tool-calling
const response = await runYourModelLoop({ messages, tools, dispatch });
// After a read-backed turn, write bounded memory in the background.
// commit derives memories from `messages` server-side; pass `memories`
// only when you have explicit facts to save, e.g. ["Prefers metric units"].
await profile.commit({
messages,
response,
});
res.json({ text: response.text });
});The first configure_profile_read call is the clearest smoke-test signal: it proves the model can call Configure through your tool router, and it gives you a real log line to inspect. Use profile.search() or configure_profile_search for concrete memories, source-specific questions, and details that need exact attribution. Use profile.remember() for one explicit fact or preference, and profile.commit() after a read-backed turn so Configure can write bounded memory.
If your app deliberately owns a preloaded approved context slot, choose the sections it needs. Valid sections are identity, preferences, integrations, imports, agents, and summary:
ts
const read = await profile.read({ sections: ["identity", "preferences", "summary"] });
const approvedContext = read.profile.format({ guidelines: false });Keep configure_profile_read and configure_profile_search in profile.tools() so the model can refresh the overview or retrieve specific memories during the turn and so you can verify the model-to-tool path.
6. Verify the first tool call
Track these success events separately:
Configure SSO connected- the user completed Continue with Configure and your backend stored server-side tokens.configure:linked- the user completed inline Configure Link and your backend stored a fallback token.configure_profile_readviaprofile.executeTool()- the model or smoke test made a Configure tool call.
To verify the tool path without a model, execute the read tool directly:
ts
const result = await profile.executeTool({
name: "configure_profile_read",
arguments: { sections: ["identity", "summary", "preferences", "imports"] },
});A non-error result confirms your keys, agent handle, token, and tool path are wired correctly.
7. Show the reading state
After SSO or configure:linked, chat apps may show <configure-runtime-reading> while the first backend profile read and response are in flight. Keep it visible for at least 1200ms, then remove it as soon as the agent response is ready.
html
<configure-runtime-reading
agent-name="Your Agent"
message="Reading approved profile">
</configure-runtime-reading>App-local users
If a user has not linked or signed in with Configure yet but your product has a stable user ID, use an app-local unlinked profile on the server:
ts
const profile = configure.profile({ externalId: "customer-123" });Unlinked profiles are developer-scoped. They are not federated across developers until the user links through Configure Link or signs in with Configure.