--- title: "User Profiles" sidebarTitle: "User Profiles" description: "Fetch and use automatically maintained user context" icon: "user" --- User profiles are extremely short summaries of context about an entity (Usually a user, but can be anything) which includes both the *static* facts about them, as well as a few recent episodes. > You can think of these as a dynamic compaction that's done by supermemory in real-time. This profile should be injected into the agent context for truly personalized experiences. To read more, visit [User profiles - Concept](/concepts/user-profiles) Get a user's profile — their static facts and dynamic context — with a single API call. Profiles are built automatically as you [ingest content](/add-memories). No setup required. ## Quick Start ```typescript import Supermemory from 'supermemory'; const client = new Supermemory(); const { profile } = await client.profile({ containerTag: "user_123" }); console.log(profile.static); // Long-term facts console.log(profile.dynamic); // Recent context ``` ```python from supermemory import Supermemory client = Supermemory() result = client.profile(container_tag="user_123") print(result.profile.static) # Long-term facts print(result.profile.dynamic) # Recent context ``` ```bash curl -X POST "https://api.supermemory.ai/v4/profile" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"containerTag": "user_123"}' ``` **Response:** ```json { "profile": { "static": [ "User is a software engineer", "User specializes in Python and React", "User prefers dark mode interfaces" ], "dynamic": [ "User is working on Project Alpha", "User recently started learning Rust", "User is debugging authentication issues" ] } } ``` --- ## Profile + Search Get profile and search results in one call by adding the `q` parameter: ```typescript const result = await client.profile({ containerTag: "user_123", q: "deployment errors" }); // Profile data const { static: facts, dynamic: context } = result.profile; // Search results (only if q was provided) const memories = result.searchResults?.results || []; ``` ```python result = client.profile( container_tag="user_123", q="deployment errors" ) # Profile data facts = result.profile.static context = result.profile.dynamic # Search results memories = result.search_results.results if result.search_results else [] ``` --- ## Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `containerTag` | string | Yes | User/project identifier | | `q` | string | No | Search query (includes search results in response) | | `threshold` | 0-1 | No | Filter search results by relevance score | | `filters` | object | No | Metadata filters applied to profile and search results | | `include` | string[] | No | Sections to return — any of `"static"`, `"dynamic"`, `"buckets"`. Omit to return all | | `buckets` | string[] | No | Restrict the `buckets` section to specific keys. Omit for all configured buckets | --- ## Building Prompts The most common pattern — inject profile into your LLM's system prompt: ```typescript async function chat(userId: string, message: string) { const { profile } = await client.profile({ containerTag: userId }); const systemPrompt = `You are assisting a user. ABOUT THE USER: ${profile.static?.join('\n') || 'No profile yet.'} CURRENT CONTEXT: ${profile.dynamic?.join('\n') || 'No recent activity.'} Personalize responses to their expertise and preferences.`; return llm.chat({ messages: [ { role: "system", content: systemPrompt }, { role: "user", content: message } ] }); } ``` --- ## Full Context Pattern Get profile + query-specific memories in one call: ```typescript async function getContext(userId: string, query: string) { const result = await client.profile({ containerTag: userId, q: query, threshold: 0.6 }); return ` User Background: ${result.profile.static.join('\n')} Current Context: ${result.profile.dynamic.join('\n')} Relevant Memories: ${result.searchResults?.results.map(m => m.memory).join('\n') || 'None'} `; } ``` --- ## Profile Buckets Buckets are **custom topical categories** for a profile — an axis that sits alongside `static` and `dynamic`. Where static/dynamic split facts by how long-lived they are, buckets group them by subject (e.g. `preferences`, `goals`, `work`). As content is ingested, a classifier assigns each memory to the buckets it matches, so you can pull just the slice of context a given surface needs. Every org starts with a built-in `preferences` bucket. You can define your own at the organization or space level in your console settings; space-level buckets are **add-only** — a container tag inherits all org buckets and may add more, but cannot disable them. ### Requesting buckets Pass `include: ["buckets"]` to return bucket-organized memories, and optionally `buckets` to limit the response to specific keys. `include` also lets you skip sections you don't need — `["buckets"]` alone omits `static` and `dynamic`. ```typescript const res = await fetch("https://api.supermemory.ai/v4/profile", { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ containerTag: "user_123", include: ["buckets"], buckets: ["preferences", "goals"] // optional — omit for all buckets }) }); const { profile } = await res.json(); console.log(profile.buckets.preferences); console.log(profile.buckets.goals); ``` ```bash curl -X POST "https://api.supermemory.ai/v4/profile" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "containerTag": "user_123", "include": ["buckets"], "buckets": ["preferences", "goals"] }' ``` **Response:** ```json { "profile": { "buckets": { "preferences": [ "[Summary] Prefers concise, technical answers and dark-mode tooling", "[Recent] Switched their editor to Zed" ], "goals": [ "[Recent] Wants to ship the billing revamp this quarter" ] } } } ``` **`[Recent]` and `[Summary]` labels.** To keep profiles dense, an entity's older memories are periodically aggregated into a short synthesis. Entries prefixed `[Summary]` are that aggregated context; entries prefixed `[Recent]` were ingested since the last aggregation and aren't summarized yet. The `dynamic` section uses the same `[Recent]` prefix (plus a `[YYYY-MM-DD]` date). Strip the prefixes if you only want raw text, or keep them to signal recency to your model. ### List bucket definitions To see which buckets are configured for a container tag (org buckets merged with any space-level additions), call `/v4/profile/buckets`: ```typescript const res = await fetch("https://api.supermemory.ai/v4/profile/buckets", { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ containerTag: "user_123" }) }); const { buckets } = await res.json(); // [{ key: "preferences", description: "..." }, ...] ``` ```bash curl -X POST "https://api.supermemory.ai/v4/profile/buckets" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"containerTag": "user_123"}' ``` **Response:** ```json { "buckets": [ { "key": "preferences", "description": "Explicit first-person preferences the person directly stated." } ] } ``` | Field | Type | Description | |-------|------|-------------| | `buckets[].key` | string | Stable slug, also stored on each memory. Lowercase alphanumeric with `-`/`_`, 1–64 chars | | `buckets[].description` | string | What belongs in the bucket — guides the ingestion classifier | Bucket descriptions steer classification. A precise description ("Explicit first-person preferences only — exclude inferred traits") yields cleaner buckets than a vague one. `static` and `dynamic` are reserved and can't be used as bucket keys. --- ## Framework Examples ```typescript async function withProfile(req, res, next) { if (!req.user?.id) return next(); try { const { profile } = await client.profile({ containerTag: req.user.id }); req.userProfile = profile; } catch (e) { req.userProfile = null; } next(); } app.use(withProfile); app.post('/chat', (req, res) => { // req.userProfile available in all routes }); ``` ```typescript // app/api/chat/route.ts export async function POST(req: NextRequest) { const { userId, message } = await req.json(); const { profile } = await client.profile({ containerTag: userId }); const response = await generateResponse(message, profile); return NextResponse.json({ response }); } ``` ```typescript import { withSupermemory } from "@supermemory/tools/ai-sdk" import { openai } from "@ai-sdk/openai" // Profiles automatically injected const model = withSupermemory(openai("gpt-4"), { containerTag: "user-123", customId: "conv-1", }) const result = await generateText({ model, messages: [{ role: "user", content: "Help with my project" }] }); ``` See [AI SDK Integration](/integrations/ai-sdk) for details. --- ## Response Schema ```typescript interface ProfileResponse { profile: { static?: string[]; // Long-term facts dynamic?: string[]; // Recent context buckets?: Record; // Topical buckets, keyed by bucket key }; searchResults?: { // Only if q parameter provided results: SearchResult[]; total: number; timing: number; }; } ``` --- ## Next Steps - [User Profiles Concept](/concepts/user-profiles) — Understand static vs dynamic - [Ingesting Content](/add-memories) — Build profiles by adding content - [AI SDK Integration](/integrations/ai-sdk) — Automatic profile injection