---
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.

<Tip>
Profiles are built automatically as you [ingest content](/add-memories). No setup required.
</Tip>

## Quick Start

<Tabs>
  <Tab title="TypeScript">
    ```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
    ```
  </Tab>
  <Tab title="Python">
    ```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
    ```
  </Tab>
  <Tab title="cURL">
    ```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"}'
    ```
  </Tab>
</Tabs>

**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:

<Tabs>
  <Tab title="TypeScript">
    ```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 || [];
    ```
  </Tab>
  <Tab title="Python">
    ```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 []
    ```
  </Tab>
</Tabs>

---

## 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`.

<Tabs>
  <Tab title="fetch">
    ```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);
    ```
  </Tab>
  <Tab title="cURL">
    ```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"]
      }'
    ```
  </Tab>
</Tabs>

**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"
      ]
    }
  }
}
```

<Note>
**`[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.
</Note>

### 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`:

<Tabs>
  <Tab title="fetch">
    ```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: "..." }, ...]
    ```
  </Tab>
  <Tab title="cURL">
    ```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"}'
    ```
  </Tab>
</Tabs>

**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 |

<Tip>
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.
</Tip>

---

## Framework Examples

<Accordion title="Express.js Middleware">
  ```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
  });
  ```
</Accordion>

<Accordion title="Next.js API Route">
  ```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 });
  }
  ```
</Accordion>

<Accordion title="AI SDK Integration">
  ```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.
</Accordion>

---

## Response Schema

```typescript
interface ProfileResponse {
  profile: {
    static?: string[];                    // Long-term facts
    dynamic?: string[];                   // Recent context
    buckets?: Record<string, string[]>;   // 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
