---
title: "Quickstart"
description: "Ingest a conversation and a document, then use document search, memory graph traversal, and profiles — and wire it into a chat harness."
icon: "play"
---
By the end of this page you will:
1. **Ingest a conversation** (how personal memory actually arrives)
2. **Ingest a document** (how knowledge for RAG arrives)
3. **Retrieve three ways** — document search (RAG), memory graph traversal, and user profile
4. **Drop it into a chat harness** that remembers across restarts
Same `containerTag` for everything. One engine, three ways out.
## Get an API key
Grab a key from the [developer console](https://console.supermemory.ai) — **API Keys → Create API Key**.
**console.supermemory.ai** is where keys and usage live. **app.supermemory.ai** is the consumer product on the same engine — not where you mint API keys.
```bash TypeScript
npm install supermemory
export SUPERMEMORY_API_KEY="sm_..."
```
```bash Python
pip install supermemory
export SUPERMEMORY_API_KEY="sm_..."
```
```bash curl
export SUPERMEMORY_API_KEY="sm_..."
```
## 1. Ingest a conversation
Real apps do not push four isolated one-liners as separate “memories.” They send **conversation turns** — often the full session — under a stable `customId` so the pipeline can extract facts and link entities.
We’ll use one user (`user_4f8a`) and one chat session. The turns never say “Sarah *is* my VP of Product” — that connection is what the graph should resolve later.
```typescript TypeScript
import Supermemory from "supermemory";
const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
const user = "user_4f8a";
const conversation = `
user: Just got back from Tokyo — the team offsite went great.
assistant: Glad it went well! Anything stand out?
user: Sarah presented the Q3 roadmap at the offsite.
assistant: Sounds like a big moment for her.
user: She's being promoted to VP of Product.
assistant: Congrats to Sarah — that's huge.
user: I need a gift idea for my VP of Product.
assistant: Happy to help brainstorm something personal.
`.trim();
const conv = await client.add({
content: conversation,
containerTag: user,
customId: "chat_offsite_2026", // one session → one document
metadata: { type: "conversation" },
dreaming: "instant", // process this document now — see note below
});
console.log(conv.id, conv.status); // e.g. "queued"
```
```python Python
from supermemory import Supermemory
client = Supermemory()
user = "user_4f8a"
conversation = """
user: Just got back from Tokyo — the team offsite went great.
assistant: Glad it went well! Anything stand out?
user: Sarah presented the Q3 roadmap at the offsite.
assistant: Sounds like a big moment for her.
user: She's being promoted to VP of Product.
assistant: Congrats to Sarah — that's huge.
user: I need a gift idea for my VP of Product.
assistant: Happy to help brainstorm something personal.
""".strip()
conv = client.add(
content=conversation,
container_tag=user,
custom_id="chat_offsite_2026",
metadata={"type": "conversation"},
dreaming="instant", # process this document now — see note below
)
print(conv.id, conv.status)
```
```bash curl
curl -X POST "https://api.supermemory.ai/v3/documents" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "user: Just got back from Tokyo — the team offsite went great.\nassistant: Glad it went well! Anything stand out?\nuser: Sarah presented the Q3 roadmap at the offsite.\nassistant: Sounds like a big moment for her.\nuser: She is being promoted to VP of Product.\nassistant: Congrats to Sarah — that is huge.\nuser: I need a gift idea for my VP of Product.\nassistant: Happy to help brainstorm something personal.",
"containerTag": "user_4f8a",
"customId": "chat_offsite_2026",
"metadata": { "type": "conversation" },
"dreaming": "instant"
}'
```
`add` returns immediately with `status: "queued"`. Processing is still **async** — wait until `done` before searching.
**`dreaming: "instant"`** — By default, dreaming is `"dynamic"`: Supermemory may batch related documents so memories form from coherent units, which can lag after `status: "done"`. For this quickstart (and any path where you need memories/profiles right away), pass **`dreaming: "instant"`** so the document is processed on its own as soon as it finishes indexing. That bills one extra operation per document. See [Processing Modes](/ingestion/add-memories#processing-modes).
## 2. Ingest a document
Now add **knowledge** the agent should ground on — a short internal note the conversation never fully spelled out. This is the SuperRAG / document path.
```typescript TypeScript
const handbook = `
# Team notes — gifts & recognition
When someone is promoted to VP or above, the company recommends a thoughtful gift
in the $75–$150 range. Experiences tied to recent team milestones land better
than generic swag.
For product leadership, books on platform strategy or a dinner near the last
offsite city are common picks. Tokyo offsites often inspire travel-themed gifts.
`.trim();
const doc = await client.add({
content: handbook,
containerTag: user,
customId: "doc_gift_policy",
metadata: { type: "document", source: "handbook" },
taskType: "superrag"
});
console.log(doc.id, doc.status);
```
```python Python
handbook = """
# Team notes — gifts & recognition
When someone is promoted to VP or above, the company recommends a thoughtful gift
in the $75–$150 range. Experiences tied to recent team milestones land better
than generic swag.
For product leadership, books on platform strategy or a dinner near the last
offsite city are common picks. Tokyo offsites often inspire travel-themed gifts.
""".strip()
doc = client.add(
content=handbook,
container_tag=user,
custom_id="doc_gift_policy",
metadata={"type": "document", "source": "handbook"},
task_type="superrag"
)
print(doc.id, doc.status)
```
```bash curl
curl -X POST "https://api.supermemory.ai/v3/documents" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "# Team notes — gifts & recognition\n\nWhen someone is promoted to VP or above, the company recommends a thoughtful gift in the $75–$150 range. Experiences tied to recent team milestones land better than generic swag.\n\nFor product leadership, books on platform strategy or a dinner near the last offsite city are common picks. Tokyo offsites often inspire travel-themed gifts.",
"containerTag": "user_4f8a",
"customId": "doc_gift_policy",
"metadata": { "type": "document", "source": "handbook" },
"taskType": "superrag"
}'
```
## 3. Wait until both are `done`
Poll document status. With **`dreaming: "instant"`**, once status is `done` the document is indexed **and** memories for that document should be available for search and profiles (`queued → extracting → … → done`).
> Note that the preferred way is to have `dreaming: dynamic`. supermemory charges one extra operation for instant dreaming. Instant is good for one off tests, setup, debugging and benchmarking.
```typescript TypeScript
async function waitUntilDone(id: string) {
for (;;) {
const d = await client.documents.get(id);
if (d.status === "done" || d.status === "failed") return d;
await new Promise((r) => setTimeout(r, 1500));
}
}
await waitUntilDone(conv.id);
await waitUntilDone(doc.id);
console.log("ready to search");
```
```python Python
import time
def wait_until_done(doc_id: str):
while True:
d = client.documents.get(doc_id)
if d.status in ("done", "failed"):
return d
time.sleep(1.5)
wait_until_done(conv.id)
wait_until_done(doc.id)
print("ready to search")
```
```bash curl
# replace DOC_ID with each document id from the add responses
curl "https://api.supermemory.ai/v3/documents/DOC_ID" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
# repeat until "status": "done"
```
Short text with instant dreaming usually finishes in a few seconds. Larger PDFs take longer. If you omit `dreaming` (default `"dynamic"`), document RAG can work after `done` while memory extraction may still be batching — use `"instant"` when the next step is memory search or profiles.
## 4. Three ways to get context back
### A. Document search (RAG)
Chunk-level retrieval over raw knowledge — use when you need **what the docs say**.
```typescript TypeScript
const rag = await client.search({
q: "gift ideas for a VP promotion after a Tokyo offsite",
containerTag: user,
searchMode: "documents",
limit: 3,
});
for (const hit of rag.results) {
console.log(hit.title ?? hit.id);
for (const chunk of hit.chunks ?? []) {
console.log(" ", chunk.content?.slice(0, 160));
}
}
```
```python Python
rag = client.search.memories(
q="gift ideas for a VP promotion after a Tokyo offsite",
container_tag=user,
search_mode="documents",
limit=3,
)
for hit in rag.results:
print(getattr(hit, "title", None) or hit.id)
for chunk in hit.chunks or []:
print(" ", (chunk.content or "")[:160])
```
```bash curl
curl -X POST "https://api.supermemory.ai/v3/search" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"q": "gift ideas for a VP promotion after a Tokyo offsite",
"containerTag": "user_4f8a",
"searchMode": "documents",
"limit": 3
}'
```
You should see chunks from the handbook (budget range, Tokyo offsite angle) — **document grounding**, not personal facts.
Switch `searchMode` to `"hybrid"` to get extracted memories and document chunks together:
```typescript
await client.search({
q: "gift ideas for a VP promotion after a Tokyo offsite",
containerTag: user,
searchMode: "hybrid",
limit: 5,
});
```
### B. Memory graph traversal
Search **extracted memories** with related edges. This is the entity-chain moment: gift → VP of Product → Sarah → Tokyo offsite.
```typescript TypeScript
const memories = await client.search({
q: "What gift should I get, and why?",
containerTag: user,
searchMode: "memories",
include: { relatedMemories: true },
limit: 5,
});
console.log(JSON.stringify(memories, null, 2));
```
```python Python
memories = client.search.memories(
q="What gift should I get, and why?",
container_tag=user,
search_mode="memories",
include={"relatedMemories": True},
limit=5,
)
print(memories)
```
```bash curl
curl -X POST "https://api.supermemory.ai/v4/search" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"q": "What gift should I get, and why?",
"containerTag": "user_4f8a",
"searchMode": "memories",
"include": { "relatedMemories": true },
"limit": 5
}'
```
Abbreviated shape:
```json
{
"results": [
{
"memory": "Sarah is being promoted to VP of Product",
"similarity": 0.81,
"context": {
"parents": [
{
"memory": "Sarah presented the Q3 roadmap at the Tokyo offsite",
"relation": "extends"
}
],
"children": [
{
"memory": "User needs a gift idea for their VP of Product, Sarah",
"relation": "derives"
}
]
}
}
],
"timing": 287
}
```
You never wrote “Sarah is my VP of Product” as one sentence. The graph connected sessions of speech. Deep dive: [graph memory](/concepts/graph-memory).
### C. User profile
Profiles are the **always-on** summary (static + recent dynamic) of an entity (or a `containerTag`) - what you inject every turn without re-searching the world.
```typescript TypeScript
const { profile, searchResults } = await client.profile({
containerTag: user,
q: "gift for the person being promoted", // optional: also run search
});
console.log("static:", profile.static);
console.log("dynamic:", profile.dynamic);
console.log("search hits:", searchResults?.results?.length ?? 0);
```
```python Python
result = client.profile(
container_tag=user,
q="gift for the person being promoted",
)
print("static:", result.profile.static)
print("dynamic:", result.profile.dynamic)
print("search hits:", len(result.search_results.results) if result.search_results else 0)
```
```bash curl
curl -X POST "https://api.supermemory.ai/v4/profile" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"containerTag": "user_4f8a",
"q": "gift for the person being promoted"
}'
```
> There is a lot more to profiles - with [Buckets](/user-profiles/buckets), for example, you can make supermemory learn and categorize incoming information for learning specific things.
| Path | Use when |
|---|---|
| **Document search** | Ground in policies, docs, handbooks |
| **Memory + related** | Personal facts, entity links, “what’s true about this user” |
| **Profile** | Cheap always-on context every LLM turn |
Same `containerTag` → same context pool. See [Memory vs RAG](/concepts/memory-vs-rag).
## 5. Put it in a harness
There is no single required harness. The pattern is the same wherever you run the model: **read** context (profile / search / docs), generate, **write** the turn back under a stable `customId` so the session stays one document.
Here are two example shapes — pick whatever matches your stack.
### Example: explicit profile + search + add
```typescript TypeScript
// npm install supermemory openai
import Supermemory from "supermemory";
import OpenAI from "openai";
import * as readline from "node:readline/promises";
const memory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY });
const llm = new OpenAI();
const user = "user_4f8a";
const sessionId = "chat_live_session";
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
while (true) {
const question = await rl.question("you: ");
const { profile, searchResults } = await memory.profile({
containerTag: user,
q: question,
});
// optional: also pull document chunks for grounding
const rag = await memory.search({
q: question,
containerTag: user,
searchMode: "documents",
limit: 3,
});
const docBits = rag.results
.flatMap((r) => r.chunks ?? [])
.map((c) => c.content)
.filter(Boolean)
.slice(0, 3);
const context = [
"## Profile (static)",
...profile.static,
"## Profile (dynamic)",
...profile.dynamic,
"## Related memories",
...(searchResults?.results?.map((m) => m.memory).filter(Boolean) ?? []),
"## Docs",
...docBits,
].join("\n");
const res = await llm.chat.completions.create({
model: "gpt-4o",
messages: [
{ role: "system", content: `You help this user. Context:\n${context}` },
{ role: "user", content: question },
],
});
const answer = res.choices[0].message.content ?? "";
console.log(`assistant: ${answer}`);
// append this turn into the same conversation document
await memory.add({
content: `user: ${question}\nassistant: ${answer}`,
containerTag: user,
customId: sessionId,
});
}
```
```python Python
# pip install supermemory openai
from supermemory import Supermemory
from openai import OpenAI
memory = Supermemory()
llm = OpenAI()
user = "user_4f8a"
session_id = "chat_live_session"
while True:
question = input("you: ")
result = memory.profile(container_tag=user, q=question)
rag = memory.search.memories(
q=question, container_tag=user, search_mode="documents", limit=3
)
doc_bits = []
for hit in rag.results:
for chunk in hit.chunks or []:
if chunk.content:
doc_bits.append(chunk.content[:300])
if len(doc_bits) >= 3:
break
memories = result.search_results.results if result.search_results else []
context = "\n".join(
[
"## Profile (static)",
*result.profile.static,
"## Profile (dynamic)",
*result.profile.dynamic,
"## Related memories",
*[m.memory for m in memories if m.memory],
"## Docs",
*doc_bits,
]
)
res = llm.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"You help this user. Context:\n{context}"},
{"role": "user", "content": question},
],
)
answer = res.choices[0].message.content or ""
print(f"assistant: {answer}")
memory.add(
content=f"user: {question}\nassistant: {answer}",
container_tag=user,
custom_id=session_id,
)
```
### Example: Vercel AI SDK
Same pattern, wrapped: `withSupermemory` injects context and can save the conversation for you. Details: [AI SDK integration](/integrations/ai-sdk).
```typescript
// npm install ai @ai-sdk/openai @supermemory/tools
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { withSupermemory } from "@supermemory/tools/ai-sdk";
import * as readline from "node:readline/promises";
const model = withSupermemory(openai("gpt-4o"), {
containerTag: "user_4f8a",
customId: "chat_live_session", // keep stable for the whole session
mode: "full", // profile + query search
});
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
while (true) {
const prompt = await rl.question("you: ");
const { text } = await generateText({ model, prompt });
console.log(`assistant: ${text}`);
}
```
Try:
```
you: What gift should I get for the person being promoted?
assistant: You're looking for something for Sarah — she's being promoted to VP of
Product after presenting the Q3 roadmap in Tokyo. Your handbook suggests $75–$150
and something tied to the offsite; a Tokyo-inspired experience or platform-strategy
book would fit…
```
### Kill it, restart it
Ctrl+C the process, start again with the **same** `containerTag` (and optional same `customId` for the live session). Ask:
```
you: who's getting promoted?
assistant: Sarah — she's being promoted to VP of Product.
```
Nothing was reloaded from your process. Memory and docs live in supermemory.
## Mental model
```
INGEST WAIT RETRIEVE
────── ──── ────────
Conversation (customId) → status === done → Memory graph (+ related)
Document (customId) → status === done → Document search (RAG)
→ Profile (static + dynamic)
│
▼
Chat harness
```
## Where next
Conversations, files, URLs, customId updates, and status.
Hybrid vs memories, filters, thresholds, rerank.
How relations and entity chains are produced.
Static vs dynamic, and when to inject a profile every turn.
withSupermemory modes, customId, addMemory.
Isolation for multi-tenant products.