Mem0 (pronounced "mem-zero") is a memory layer for AI agents and applications. It lets your LLM apps remember facts about users, agents, and conversations across sessions, so they stop forgetting everything the moment a chat ends.
You give Mem0 conversation messages; it uses an LLM to extract the durable facts ("User is allergic to peanuts", "User switched from almond to oat milk"), stores them as searchable memories, and returns the most relevant ones whenever you ask. The result is personalization that persists — without you stuffing an ever-growing transcript into every prompt.
This guide shows you how to install Mem0, store and search memories, scope them to users and agents, and wire Mem0 into real applications using Python, TypeScript, the REST API, or the command line. Configuration reference, deployment, and internals live in the companion Admin Guide.
Table of Contents
- Quick Start
- Choosing Your Path: Platform vs Open Source
- Installation
- Core Concepts
- Everyday Usage: The Memory Operations
- Scoping Memories: Users, Agents, Runs
- Searching and Filtering
- The Open Source Library in Depth
- The Platform Client in Depth
- The Mem0 CLI
- The LLM Proxy: Memory-Aware Chat in One Call
- The REST API
- OpenMemory: Your Private Memory Server
- Integrations
- Common Workflows (Recipes)
- How Mem0 Works (Concepts)
- Troubleshooting
- Frequently Asked Questions
- Reference
1. Quick Start
The fastest way to see Mem0 work is the managed Platform: get an API key, add a memory, search it back.
Python
pip install mem0ai
export MEM0_API_KEY="m0-your-api-key"
from mem0 import MemoryClient
client = MemoryClient() # reads MEM0_API_KEY from the environment
# Store a conversation — Mem0 extracts the durable facts
client.add(
[
{"role": "user", "content": "I'm vegetarian and allergic to nuts."},
{"role": "assistant", "content": "Got it — I'll keep that in mind."},
],
user_id="alex",
)
# Later, in a different session, recall what matters
results = client.search("What can I cook for Alex?", filters={"user_id": "alex"})
for m in results["results"]:
print(m["memory"])
Is vegetarian
Is allergic to nuts
TypeScript
npm install mem0ai
export MEM0_API_KEY="m0-your-api-key"
import MemoryClient from "mem0ai";
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY });
await client.add(
[
{ role: "user", content: "I'm vegetarian and allergic to nuts." },
{ role: "assistant", content: "Got it — I'll keep that in mind." },
],
{ user_id: "alex" }
);
const results = await client.search("What can I cook for Alex?", {
filters: { user_id: "alex" },
});
console.log(results);
cURL
curl -X POST https://api.mem0.ai/v3/memories/add/ \
-H "Authorization: Token m0-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "I am vegetarian and allergic to nuts."}
],
"user_id": "alex"
}'
Tip
Get a Platform API key from the Mem0 dashboard. Platform keys start with
m0-. No infrastructure to run — Mem0 hosts the LLM, embeddings, and vector store for you.
Note
Prefer to run everything yourself with no external service? Skip to the Open Source Library. You only need an OpenAI (or other provider) key and a vector store — Mem0 handles the rest locally.
2. Choosing Your Path: Platform vs Open Source
Mem0 ships as one package with two ways to use it. Pick the one that fits your situation.
Platform (MemoryClient) |
Open Source (Memory) |
|
|---|---|---|
| Where memories live | Mem0's managed cloud (api.mem0.ai) |
Your own vector store + database |
| What you provide | A Mem0 API key | LLM key + a vector store |
| Infrastructure to run | None | Vector store (Qdrant, pgvector, etc.) |
| Best for | Shipping fast, scaling without ops | Full data control, on-prem, air-gapped |
| Extra features | Webhooks, exports, projects, feedback, graph memory | Pluggable providers, local-first |
| Import (Python) | from mem0 import MemoryClient |
from mem0 import Memory |
| Import (TS) | import MemoryClient from "mem0ai" |
import { Memory } from "mem0ai/oss" |
Important
The two share the same core verbs —
add,search,get,get_all,update,delete,history— but their method signatures differ slightly (the Platform client accepts more options likeapp_id, webhooks, and exports). Examples in this guide are labelled so you always know which one you're looking at.
You can start on the Platform and move to self-hosted later (or vice versa); your application code barely changes because the verbs are the same.
3. Installation
Requirements
| Requirement | Platform | Open Source |
|---|---|---|
| Python | 3.10+ | 3.10+ |
| Node.js (for TS/JS or CLI) | 18+ | 18+ |
| Mem0 API key | Required | — |
LLM provider key (e.g. OPENAI_API_KEY) |
— | Required |
| Vector store | — | Required (Qdrant by default) |
Python
Platform only
pip install mem0ai
Open Source (with NLP extras)
pip install "mem0ai[nlp]"
python -m spacy download en_core_web_sm
Note
The open-source library uses spaCy for keyword lemmatization and entity extraction (part of its hybrid search). Installing the
[nlp]extra and theen_core_web_smmodel unlocks the full retrieval quality. If spaCy is missing, Mem0 still works — it falls back to semantic-only search.
TypeScript / JavaScript
npm install mem0ai
# or
pnpm add mem0ai
# or
yarn add mem0ai
The npm package mem0ai exposes the Platform client at the root and the open-source implementation under the mem0ai/oss subpath:
import MemoryClient from "mem0ai"; // Platform
import { Memory } from "mem0ai/oss"; // Open Source
Command Line
npm install -g mem0ai # installs the `mem0` command (via @mem0/cli)
See The Mem0 CLI for usage.
Setting your keys
macOS / Linux
export MEM0_API_KEY="m0-your-api-key" # Platform
export OPENAI_API_KEY="sk-..." # Open Source default LLM/embedder
Windows (PowerShell)
setx MEM0_API_KEY "m0-your-api-key"
setx OPENAI_API_KEY "sk-..."
Python (.env)
from dotenv import load_dotenv
load_dotenv() # loads MEM0_API_KEY / OPENAI_API_KEY from a .env file
4. Core Concepts
A handful of ideas appear everywhere in Mem0. Learn them once.
Memory
: A single durable fact extracted from conversation, e.g. "User is allergic to nuts". Each memory has an id, the memory text, a hash, timestamps, and any metadata you attached. Memories are stored as vectors so they can be searched by meaning.
Messages
: The input you feed add(). Either a plain string ("I love hiking") or a list of chat messages ([{"role": "user", "content": "..."}]). Mem0 reads these and decides what's worth remembering.
Inference
: By default (infer=True), Mem0 sends your messages to an LLM that extracts only the memorable facts — not the whole transcript. Set infer=False to store messages verbatim with no LLM processing.
Scope (entity IDs)
: Every memory belongs to at least one of user_id, agent_id, or run_id (the Platform also supports app_id). These keep one user's memories separate from another's. You must provide at least one when adding or searching.
Search
: A meaning-based lookup. You give a query like "What does Alex eat?" and Mem0 returns the most relevant memories, ranked by a hybrid of semantic similarity, keyword matching, and entity overlap.
Tip
Think of
add()as "tell Mem0 what happened" andsearch()as "ask Mem0 what it knows." You typically calladd()after each conversation turn andsearch()before composing your next LLM prompt.
5. Everyday Usage: The Memory Operations
Every Mem0 surface — library, client, REST, CLI — exposes the same set of operations. Here they are with the Platform Python client; later sections show the open-source and other variants.
Add a memory
from mem0 import MemoryClient
client = MemoryClient()
# From a conversation
client.add(
[
{"role": "user", "content": "Book me a window seat when I fly."},
{"role": "assistant", "content": "Noted — window seats going forward."},
],
user_id="alex",
)
# From a single string
client.add("Alex prefers morning meetings", user_id="alex")
{'results': [{'id': '0b3f...', 'memory': 'Prefers window seats on flights', 'event': 'ADD'},
{'id': '7a21...', 'memory': 'Prefers morning meetings', 'event': 'ADD'}]}
Each result carries an event describing what happened: ADD (new memory created), and on the Platform UPDATE/DELETE/NONE when an incoming fact revises or duplicates an existing one.
Search memories
results = client.search("travel preferences", filters={"user_id": "alex"})
for m in results["results"]:
print(m["memory"], "→ score", round(m["score"], 3))
Prefers window seats on flights → score 0.71
Get all memories for a scope
all_mem = client.get_all(filters={"user_id": "alex"}, page=1, page_size=50)
print(all_mem["results"])
Get one memory by ID
mem = client.get("0b3f...")
print(mem["memory"])
Update a memory
client.update("0b3f...", text="Prefers aisle seats on long flights")
{'message': 'Memory updated successfully!'}
Delete a memory
client.delete("0b3f...")
{'message': 'Memory deleted successfully!'}
Delete all memories for a scope
client.delete_all(user_id="alex")
Caution
delete_all()removes every memory matching the filter you pass. There is no undo. To wipe everything for the whole account/instance, usereset()instead — and be equally careful.
View a memory's history
for change in client.history("0b3f..."):
print(change["event"], change.get("old_memory"), "→", change.get("new_memory"))
ADD None → Prefers window seats on flights
UPDATE Prefers window seats on flights → Prefers aisle seats on long flights
Note
History is an audit trail of how a memory changed over time — when it was added, updated, or deleted. It's invaluable for debugging "why does the agent think X?"
6. Scoping Memories: Users, Agents, Runs
Scope is how Mem0 keeps memories from leaking between people, agents, and sessions. You must always supply at least one scope identifier.
| Scope ID | Meaning | Typical use |
|---|---|---|
user_id |
An end user / person | "What does this customer like?" |
agent_id |
An AI agent identity | An agent's own learned behaviors and config |
run_id |
A single session / conversation run | Short-lived, per-conversation memory |
app_id |
An application (Platform only) | Group memory by product or app |
Per-user memory (most common)
client.add(messages, user_id="alex")
client.search("preferences", filters={"user_id": "alex"})
Agent memory
When you add messages that include assistant turns and pass an agent_id, Mem0 can extract facts about the agent itself (its recommendations, configured behaviors, learned style):
client.add(
[
{"role": "user", "content": "Be concise from now on."},
{"role": "assistant", "content": "Understood — I'll keep answers short."},
],
agent_id="support-bot",
)
Combining scopes
You can scope to several IDs at once to narrow precisely:
client.add(messages, user_id="alex", agent_id="support-bot", run_id="ticket-8842")
client.search("open issues", filters={"user_id": "alex", "run_id": "ticket-8842"})
Important
In
search()andget_all(), entity IDs must go insidefilters={...}, not as top-level arguments.client.search(query, user_id="alex")raises an error in current versions; useclient.search(query, filters={"user_id": "alex"}). Inadd()anddelete_all(), they remain top-level arguments (user_id="alex"). This split is deliberate — it keeps "where to store" separate from "what to query."
7. Searching and Filtering
Search is where Mem0 earns its keep. Beyond a plain query, you can filter on metadata, use comparison operators, and combine conditions with boolean logic.
Basic search
client.search("dietary restrictions", filters={"user_id": "alex"})
Limit results and set a threshold
client.search(
"favorite foods",
filters={"user_id": "alex"},
top_k=5, # return at most 5 memories
threshold=0.3, # drop matches below this similarity score (0–1)
)
Metadata filters with operators
When you store memories with custom metadata, you can filter on it using rich operators. Pass the operator as a nested dict:
# Memories tagged with a category, created this year, excluding archived ones
client.search(
"project notes",
filters={
"user_id": "alex",
"category": {"in": ["work", "planning"]},
"year": {"gte": 2026},
"status": {"ne": "archived"},
},
)
Supported operators (open-source and Platform):
| Operator | Meaning | Example |
|---|---|---|
eq |
equals | {"tier": {"eq": "pro"}} |
ne |
not equals | {"status": {"ne": "archived"}} |
gt / gte |
greater than / or equal | {"year": {"gte": 2026}} |
lt / lte |
less than / or equal | {"score": {"lte": 5}} |
in |
value in list | {"tag": {"in": ["a", "b"]}} |
nin |
value not in list | {"tag": {"nin": ["spam"]}} |
contains |
substring match | {"note": {"contains": "urgent"}} |
icontains |
case-insensitive substring | {"note": {"icontains": "Urgent"}} |
"*" |
wildcard (any value present) | {"category": "*"} |
Boolean logic: AND / OR / NOT
client.search(
"travel",
filters={
"user_id": "alex",
"OR": [
{"category": "flights"},
{"category": "hotels"},
],
"NOT": [{"status": "cancelled"}],
},
)
Tip
Keep
user_id/agent_id/run_idat the top level offilterseven when you useAND/OR/NOT— those entity IDs always scope the search, while the boolean blocks refine within that scope.
Reranking for higher precision
Set rerank=True to re-score the top candidates with a dedicated reranker model for sharper ordering (slower, but more accurate):
client.search("what to pack for the trip", filters={"user_id": "alex"}, rerank=True)
Note
On the open-source library, reranking requires you to configure a reranker provider (Cohere, a sentence-transformer model, etc.) — see the Admin Guide. On the Platform,
rerank=Truejust works.
8. The Open Source Library in Depth
The open-source Memory class runs entirely on your own infrastructure. You bring an LLM, an embedder, and a vector store; Mem0 orchestrates extraction, storage, and hybrid retrieval locally.
Zero-config start (Python)
With just OPENAI_API_KEY set, the defaults give you OpenAI for extraction and embeddings plus a local Qdrant store:
from mem0 import Memory
m = Memory() # uses default config
m.add(
[{"role": "user", "content": "I run every morning before work."}],
user_id="alex",
)
print(m.search("exercise habits", filters={"user_id": "alex"}))
{'results': [{'id': '...', 'memory': 'Runs every morning before work',
'score': 0.62, 'created_at': '2026-06-03T...', 'updated_at': '...'}]}
The full open-source API
| Method | Signature | Returns |
|---|---|---|
add |
add(messages, *, user_id=None, agent_id=None, run_id=None, metadata=None, infer=True, memory_type=None, prompt=None) |
{"results": [...]} |
search |
search(query, *, top_k=20, filters=None, threshold=0.1, rerank=False) |
{"results": [...]} |
get |
get(memory_id) |
memory dict or None |
get_all |
get_all(*, filters=None, top_k=20) |
{"results": [...]} |
update |
update(memory_id, data, metadata=None) |
{"message": "..."} |
delete |
delete(memory_id) |
{"message": "..."} |
delete_all |
delete_all(user_id=None, agent_id=None, run_id=None) |
{"message": "..."} |
history |
history(memory_id) |
list of change records |
reset |
reset() |
None (wipes the store) |
close |
close() |
releases DB connections |
Important
In the open-source
search()andget_all(), the entity IDs go insidefilters, and at least one ofuser_id/agent_id/run_idis required. Passinguser_id="alex"as a top-level keyword tosearch()raises aValueErrortelling you to usefilters={"user_id": "alex"}instead.
Storing raw messages without inference
m.add(
[{"role": "user", "content": "Order #4471 shipped on 2026-06-01"}],
user_id="alex",
infer=False, # store the message text directly, skip LLM extraction
)
Tip
Use
infer=Falsefor structured records you want stored verbatim (order numbers, logs, IDs) where you don't want an LLM paraphrasing them. Use the defaultinfer=Truefor natural conversation where you want clean, deduplicated facts.
Async usage
Every method has an async twin via AsyncMemory:
import asyncio
from mem0 import AsyncMemory
async def main():
m = await asyncio.to_thread(AsyncMemory)
await m.add([{"role": "user", "content": "I prefer dark mode"}], user_id="alex")
print(await m.search("ui preferences", filters={"user_id": "alex"}))
asyncio.run(main())
Configuring providers
Memory.from_config() takes a plain dict that selects your LLM, embedder, and vector store:
from mem0 import Memory
config = {
"llm": {"provider": "anthropic", "config": {"model": "claude-sonnet-4-5", "temperature": 0.1}},
"embedder": {"provider": "openai", "config": {"model": "text-embedding-3-small"}},
"vector_store": {"provider": "qdrant", "config": {"host": "localhost", "port": 6333}},
}
m = Memory.from_config(config)
The library supports a broad provider matrix out of the box:
- LLMs: OpenAI, Anthropic, Gemini, Groq, Together, AWS Bedrock, Azure OpenAI, DeepSeek, MiniMax, xAI, Sarvam, Ollama, LM Studio, vLLM, LiteLLM, LangChain.
- Embedders: OpenAI, Ollama, Hugging Face, Azure OpenAI, Gemini, Vertex AI, Together, LM Studio, AWS Bedrock, FastEmbed, LangChain.
- Vector stores: Qdrant, Chroma, pgvector, Milvus, Pinecone, Redis, Valkey, Weaviate, FAISS, Elasticsearch, OpenSearch, MongoDB, Supabase, Azure AI Search, Databricks, Vertex AI Vector Search, Upstash, S3 Vectors, Cassandra, Baidu, Neptune Analytics, Turbopuffer, plus Azure MySQL.
Note
The exact config keys for each provider (hosts, models, API-base overrides, environment variables) are catalogued in the Admin Guide → Configuration Reference. As a user, you mainly need to know that switching providers is a one-line change in the config dict.
TypeScript open-source
import { Memory } from "mem0ai/oss";
const memory = new Memory({
embedder: { provider: "openai", config: { apiKey: process.env.OPENAI_API_KEY } },
llm: { provider: "openai", config: { apiKey: process.env.OPENAI_API_KEY, model: "gpt-4o" } },
vectorStore: { provider: "memory", config: { collectionName: "memories" } },
});
await memory.add("The sky is blue", "alex");
const results = await memory.search("What color is the sky?", "alex");
Note
The TypeScript open-source build ships with sensible defaults (OpenAI embeddings + GPT-4 + an in-memory vector store + SQLite history), so a
new Memory()with just an API key works for quick experiments. Production deployments should pick a persistent vector store (pgvector, Qdrant, Redis).
9. The Platform Client in Depth
The Platform client (MemoryClient / AsyncMemoryClient) talks to Mem0's hosted API. Beyond the core verbs, it unlocks features that need server-side infrastructure.
Initialization
from mem0 import MemoryClient
client = MemoryClient(api_key="m0-...") # or rely on MEM0_API_KEY env var
# Custom host (e.g. EU region or self-hosted Platform):
client = MemoryClient(api_key="m0-...", host="https://api.mem0.ai")
import MemoryClient from "mem0ai";
const client = new MemoryClient({ apiKey: "m0-..." });
Platform-only capabilities
Batch operations — update or delete many memories in one call:
client.batch_update([
{"memory_id": "id-1", "text": "Updated fact one"},
{"memory_id": "id-2", "metadata": {"reviewed": True}},
])
client.batch_delete([{"memory_id": "id-1"}, {"memory_id": "id-2"}])
Entities (users/agents/runs) — list and manage every entity that has memories:
client.users() # all users, agents, runs with memories
client.delete_users(user_id="alex") # delete a specific entity's footprint
Memory exports — request a structured export defined by a JSON schema:
client.create_memory_export(schema=my_json_schema, user_id="alex")
export = client.get_memory_export(user_id="alex")
Summaries — get a narrative summary of a user's memories:
client.get_summary(filters={"user_id": "alex"})
Feedback — tell Mem0 a retrieved memory was good or bad to improve future results:
client.feedback(memory_id="id-1", feedback="POSITIVE")
client.feedback(memory_id="id-2", feedback="NEGATIVE", feedback_reason="outdated")
Valid feedback values: POSITIVE, NEGATIVE, VERY_NEGATIVE.
Webhooks — get notified when memories change:
client.create_webhook(
url="https://example.com/hooks/mem0",
name="memory-events",
project_id="proj_123",
event_types=["memory.add", "memory.update"],
)
client.get_webhooks(project_id="proj_123")
Projects — manage project-wide settings like custom instructions and categories:
client.project.update(
custom_instructions="Focus on travel preferences and dietary restrictions.",
custom_categories=["travel", "food", "work"],
)
Tip
Custom instructions steer what the extraction LLM remembers. If your app only cares about, say, support-ticket context, set instructions accordingly and Mem0 will stop storing irrelevant chit-chat — improving precision and lowering noise.
Deleting superseded memories — when a newer memory supersedes an older one, delete the whole chain at once:
client.delete("id-current", delete_linked=True)
Async Platform client
import asyncio
from mem0 import AsyncMemoryClient
async def main():
async with AsyncMemoryClient() as client:
await client.add("I love jazz", user_id="alex")
print(await client.search("music taste", filters={"user_id": "alex"}))
asyncio.run(main())
10. The Mem0 CLI
The mem0 command brings memory to your terminal and to coding agents. It talks to the Mem0 Platform.
Setup
npm install -g mem0ai
mem0 init # interactive: paste your API key or log in via email
init writes config to ~/.mem0/config.json (permissions 0600). You can also pass flags:
mem0 init --api-key m0-... --user-id alex
mem0 init --email [email removed] # login via emailed verification code
Core commands
# Add memory (string or piped messages)
mem0 add "I prefer TypeScript over JavaScript" --user-id alex
mem0 add --file conversation.json --user-id alex
# Search
mem0 search "language preferences" --user-id alex
mem0 search "preferences" --user-id alex --output table
# Retrieve / list
mem0 get <memoryId>
mem0 list --user-id alex --page 1
# Update / delete
mem0 update <memoryId> "Now prefers Rust"
mem0 delete <memoryId>
mem0 delete --all --user-id alex --confirm # wipe a user's memories
mem0 delete --all --user-id alex --dry-run # preview what would be deleted
# Import a JSON export
mem0 import memories.json --user-id alex
# Status & config
mem0 status
mem0 whoami
mem0 config show
mem0 config get platform.base_url
mem0 config set defaults.user_id alex
Add options worth knowing
| Flag | Effect |
|---|---|
--user-id, --agent-id, --app-id, --run-id |
Scope the memory |
--metadata <json> |
Attach custom metadata |
--immutable |
Prevent the memory from being updated later |
--no-infer |
Store raw, skip LLM extraction |
--expires <YYYY-MM-DD> |
Auto-expire the memory |
--categories <list> |
Tag with categories (JSON array or comma-separated) |
--output <format> |
text, json, or quiet |
Search options
| Flag | Effect |
|---|---|
--rerank |
Enable reranking (Platform) |
--keyword |
Use keyword search |
--filter <json> |
Advanced filter expression |
--fields <list> |
Return only specific fields |
--output <format> |
text, json, or table |
Agent / scripting mode
Every command accepts a global --json flag that emits a machine-readable envelope, ideal for use inside AI coding agents and scripts:
mem0 search "preferences" --user-id alex --json
{"status":"ok","command":"search","data":{"results":[ ... ]}}
Tip
The CLI auto-detects when it's running inside an AI coding assistant (Claude Code, Cursor, Codex, Cline, Continue, Aider, Goose, Windsurf) and switches to a quiet, JSON-friendly "agent mode" so its output is easy to parse. Set
NO_COLOR=1to disable ANSI colors anywhere.
CLI environment variables
| Variable | Purpose |
|---|---|
MEM0_API_KEY |
API key (overrides config file) |
MEM0_BASE_URL |
API base URL |
MEM0_USER_ID / MEM0_AGENT_ID / MEM0_APP_ID / MEM0_RUN_ID |
Default scope IDs |
NO_COLOR |
Disable colored output |
11. The LLM Proxy: Memory-Aware Chat in One Call
The Mem0 proxy wraps an OpenAI-compatible chat completion so memory retrieval and storage happen automatically — you make a normal chat call, and Mem0 injects relevant memories into the prompt and saves new ones in the background.
from mem0.proxy.main import Mem0
# Use the Platform...
mem0_chat = Mem0(api_key="m0-...")
# ...or the open-source library:
# mem0_chat = Mem0(config={"vector_store": {...}, "llm": {...}})
response = mem0_chat.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "What restaurant should I book tonight?"}],
user_id="alex",
)
print(response.choices[0].message.content)
What happens under the hood:
- Mem0 searches the user's memories using the last few messages as the query.
- It injects the relevant memories into a system prompt.
- It calls the model (via LiteLLM, so any supported model works).
- In a background thread, it stores the new turn as memory.
Note
The proxy requires a model that supports function calling and at least one of
user_id,agent_id, orrun_id. It installslitellmon first use if it isn't already present.
Tip
The proxy is the lowest-effort way to add memory to an existing chatbot: replace your
openai.chat.completions.create(...)withmem0.chat.completions.create(..., user_id=...)and you instantly get personalization across sessions.
12. The REST API
If you self-host the Mem0 REST server (see [Admin Guide → Deployment]), or want to call the Platform over HTTP directly, the memory operations are available as plain HTTP endpoints.
Self-hosted server endpoints
| Method | Path | Purpose |
|---|---|---|
POST |
/memories |
Create memories |
GET |
/memories |
List memories (optionally filtered by user_id/agent_id/run_id) |
GET |
/memories/{memory_id} |
Get one memory |
POST |
/search |
Search memories |
PUT |
/memories/{memory_id} |
Update a memory |
GET |
/memories/{memory_id}/history |
Memory change history |
DELETE |
/memories/{memory_id} |
Delete a memory |
DELETE |
/memories |
Delete all for a scope |
POST |
/reset |
Reset all memories |
GET/POST |
/configure |
View / set the runtime config |
Example: add and search over HTTP
# Add
curl -X POST http://localhost:8000/memories \
-H "X-API-Key: $MEM0_KEY" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"I love spicy food"}],"user_id":"alex"}'
# Search
curl -X POST http://localhost:8000/search \
-H "X-API-Key: $MEM0_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"food preferences","filters":{"user_id":"alex"}}'
Important
On
/search, pass entity IDs insidefilters(e.g."filters": {"user_id": "alex"}). Passinguser_idat the top level still works but is deprecated and logs a warning. The self-hosted server's interactive API docs live at/docs(Swagger UI) once it's running.
Platform HTTP API
The Platform exposes versioned endpoints under https://api.mem0.ai (e.g. POST /v3/memories/add/, POST /v3/memories/search/, GET /v1/memories/{id}/). Authenticate with Authorization: Token m0-your-api-key. Most users reach these through the SDKs rather than raw HTTP.
13. OpenMemory: Your Private Memory Server
OpenMemory is a self-hosted, Dockerized memory server with a web dashboard and a built-in MCP (Model Context Protocol) server, so MCP-aware clients (Claude Desktop, Cursor, etc.) can read and write your memories. Everything stays on your machine.
One-line install
curl -sL https://raw.githubusercontent.com/mem0ai/mem0/main/openmemory/run.sh \
| OPENAI_API_KEY=your_api_key bash
This script:
- Verifies Docker and Docker Compose are installed.
- Picks a vector store (default Qdrant; override with
VECTOR_STORE=...—qdrant,chroma,pgvector,redis,weaviate,milvus,elasticsearch,faiss). - Starts the backend API on
http://localhost:8765and the dashboard UI onhttp://localhost:3000(next free port up to 3010).
# Choose a different vector store
curl -sL .../openmemory/run.sh | OPENAI_API_KEY=sk-... VECTOR_STORE=pgvector bash
What you get
- A web UI to browse, search, create, and delete your memories and connected apps.
- An MCP endpoint (
/{client}/sse/{user_id}) you can register in any MCP client to give it long-term memory. - Your memories stored locally in the vector store of your choice.
Tip
OpenMemory is the best fit if you want a personal memory layer shared across all your AI tools, fully under your control, without sending data to a managed service. The only external dependency is the LLM/embedding provider key you supply (OpenAI by default).
14. Integrations
Mem0 plugs into the popular AI app frameworks. The pattern is always the same: search memories before the model call, add memories after.
| Integration | Package / entry point | Notes |
|---|---|---|
| Vercel AI SDK | @mem0/vercel-ai-provider |
Drop-in provider that adds memory to AI SDK apps |
| OpenAI Agents / tools | mem0ai + OpenAI SDK |
Use Mem0 as a tool the agent can call |
| LangChain / LangGraph | @mem0/community (mem0ai/community/langchain) |
Memory-backed chains and graphs |
| CrewAI, LlamaIndex, AutoGen | mem0ai |
Search/add around agent steps |
| OpenClaw | @mem0/openclaw-mem0 |
Mem0 memory backend for OpenClaw, platform or self-hosted |
| Claude Code | Mem0 plugin (/plugin install mem0@mem0-plugins) |
Skills that add, search, and manage memory from Claude |
Vercel AI SDK example
import { createMem0 } from "@mem0/vercel-ai-provider";
import { generateText } from "ai";
const mem0 = createMem0({ apiKey: process.env.MEM0_API_KEY });
const { text } = await generateText({
model: mem0("gpt-4o", { user_id: "alex" }),
prompt: "Recommend a dinner spot for me.",
});
Mem0 as an OpenAI tool
Expose search/add as tools your agent can call, then let the model decide when to remember or recall. The examples/openai-inbuilt-tools directory in the repo shows a complete pattern.
Note
Each integration ships runnable examples in the
examples/directory of the repository (multimodal chat, Vercel chat app, graph-DB demo, YouTube assistant Chrome extension, healthcare assistant, and more). They're the quickest way to see an end-to-end app.
15. Common Workflows (Recipes)
Recipe: Personalized chatbot
from mem0 import MemoryClient
client = MemoryClient()
def chat(user_id, user_message, llm_call):
# 1. Recall
memories = client.search(user_message, filters={"user_id": user_id}, top_k=5)
context = "\n".join(m["memory"] for m in memories["results"])
# 2. Compose prompt with memory context
system = f"You are a helpful assistant. What you know about the user:\n{context}"
reply = llm_call(system=system, user=user_message)
# 3. Remember this turn
client.add(
[{"role": "user", "content": user_message},
{"role": "assistant", "content": reply}],
user_id=user_id,
)
return reply
Recipe: Long-running agent that learns
# Store agent-level lessons that persist across runs
client.add(
[{"role": "assistant", "content": "When the user asks for code, default to Python."}],
agent_id="dev-helper",
)
# Recall them at the start of each run
lessons = client.search("coding defaults", filters={"agent_id": "dev-helper"})
Recipe: Per-session scratch memory that you clean up
run_id = "session-2026-06-03-001"
client.add(messages, user_id="alex", run_id=run_id)
# ...use it during the session...
client.delete_all(user_id="alex", run_id=run_id) # tidy up when done
Recipe: Tagging and filtered recall
client.add("Prefers Delta for transatlantic flights", user_id="alex",
metadata={"category": "travel", "confidence": "high"})
client.search("airline preference", filters={
"user_id": "alex",
"category": "travel",
"confidence": {"in": ["high", "verified"]},
})
Recipe: Bulk import existing user data
# infer=False stores facts verbatim — good for migrating known facts
for fact in known_user_facts:
client.add(fact, user_id="alex", infer=False)
Tip
A reliable pattern for production chatbots: search before every model call, add after every model call, and keep
top_kmodest (3–7). This keeps prompts small while still surfacing the facts that matter.
16. How Mem0 Works (Concepts)
You don't need this section to use Mem0, but understanding the pipeline helps you debug and tune it.
What happens on add()
When you add a conversation with inference enabled, Mem0 runs a multi-phase pipeline:
- Context gathering — pulls the recent messages for this scope to resolve pronouns and references.
- Existing-memory retrieval — embeds your messages and finds related memories already stored.
- LLM extraction — a single LLM call extracts self-contained, contextually rich facts from both user and assistant messages, deduplicating against what's already known and linking related memories.
- Embedding & dedup — each extracted fact is embedded; exact duplicates (by content hash) are skipped.
- Storage — new memories are written to the vector store, with a history record for each.
- Entity linking — named entities (people, places, titles) are extracted and linked so future searches can boost memories about the same entity.
The extraction model is careful: it preserves proper nouns, exact numbers, and dates; grounds relative time references ("last week") to absolute dates; never fabricates; and captures emotional and motivational context, not just bare facts.
What happens on search()
The open-source library uses hybrid retrieval that blends three signals:
- Semantic search — vector similarity between your query and stored memories.
- Keyword (BM25) search — lexical matching using lemmatized text, so "running" matches "ran".
- Entity boosting — memories linked to entities mentioned in your query get a relevance boost.
These signals are combined into a single normalized score, filtered by your threshold, and ranked. Optionally a reranker model re-orders the top results for maximum precision.
Note
This is why installing the spaCy NLP extras matters for the open-source library: keyword matching and entity boosting both rely on spaCy. Without it, you still get semantic search, just not the full hybrid quality.
Memory types
| Type | How to create | Use |
|---|---|---|
| Factual / conversational (default) | add(messages, user_id=...) |
Everyday user/agent facts |
| Procedural | add(messages, agent_id=..., memory_type="procedural_memory") |
A detailed summary of an agent's step-by-step execution history |
Where data lives (open source)
- Memories (vectors): your chosen vector store.
- History (audit trail): a local SQLite database at
~/.mem0/history.dbby default. - Working directory:
~/.mem0/(override with theMEM0_DIRenvironment variable).
17. Troubleshooting
Error: Mem0 API Key not provided. Please provide an API Key.
Cause: The Platform client couldn't find an API key.
Solution: Set MEM0_API_KEY in your environment or pass MemoryClient(api_key="m0-...").
Prevention: Keep the key in a .env file loaded at startup; never hard-code it in source.
Error: filters must contain at least one of: user_id, agent_id, run_id.
Cause: You called search() or get_all() without a scope inside filters.
Solution: Add a scope, e.g. search(query, filters={"user_id": "alex"}).
Prevention: Always decide a memory's scope up front; treat scope as required.
Error: Top-level entity parameters {...} are not supported in search()/get_all(). Use filters={'user_id': '...'} instead.
Cause: You passed user_id/agent_id/run_id/app_id as a top-level keyword to search() or get_all().
Solution: Move them inside filters={...}.
Prevention: Remember the rule — top-level on add()/delete_all(), inside filters on search()/get_all().
Error: Invalid threshold: ... Must be between 0 and 1
Cause: threshold was outside the [0, 1] range, or top_k was negative.
Solution: Use a threshold between 0 and 1 (default 0.1) and a non-negative integer top_k.
Error: Invalid 'memory_type'. Please pass procedural_memory ...
Cause: You passed a memory_type other than "procedural_memory".
Solution: Only "procedural_memory" is supported; omit memory_type for normal memories.
Search returns nothing even though you added memories
Cause: Usually a scope mismatch (added under one user_id, searched under another), or the threshold is too high.
Solution: Confirm you're searching the same scope you added to; lower threshold (try 0.1 or 0); call get_all(filters={"user_id": ...}) to confirm the memories exist.
Prevention: Standardize your scope IDs across add and search.
Open-source search quality feels weak / "spaCy is not installed"
Cause: The spaCy NLP model isn't installed, so keyword and entity signals are disabled.
Solution: pip install "mem0ai[nlp]" then python -m spacy download en_core_web_sm.
Prevention: Install the NLP extras as part of your environment setup.
add() returns an empty results list
Cause: The extraction LLM found nothing worth remembering (e.g. pure greetings), or all extracted facts were duplicates of existing memories.
Solution: This is expected for non-informational messages. Verify with content that contains real facts; check get_all() to see what's already stored.
Self-hosted server returns 401 Authentication required
Cause: The server has auth enabled but no credentials were supplied.
Solution: Pass a valid X-API-Key or Bearer token; for local development only, the operator can set AUTH_DISABLED=true. See the Admin Guide for auth setup.
Self-hosted server: LLM provider 'X' is not bundled in this image
Cause: You configured a provider whose Python package isn't included in the prebuilt server image. Solution: The default server image bundles OpenAI, Anthropic, and Gemini (LLM) and OpenAI/Gemini (embedder). To use another, the operator must install its package and rebuild — see the Admin Guide.
Rate limit / provider errors (provider_rate_limited, provider_timeout)
Cause: The upstream LLM/embedding provider throttled or timed out.
Solution: Retry with backoff; on the Platform, catch RateLimitError and wait. Reduce request volume or upgrade your provider tier.
18. Frequently Asked Questions
Q: Do I need to choose Platform or Open Source forever?
No. They share the same verbs, so you can prototype on the Platform and self-host later (or run both). Your add/search calls barely change.
Q: What does Mem0 actually store — the whole conversation?
By default, no. With infer=True it stores only the extracted facts (e.g. "Is vegetarian"), not the raw transcript. Use infer=False if you want messages stored verbatim.
Q: Which LLM and embedder does the open-source library use by default?
OpenAI for both — a chat model for extraction and text-embedding-3-small for embeddings — with a local Qdrant vector store. You only need OPENAI_API_KEY set. Swap any of them via config.
Q: Can I run Mem0 fully offline / air-gapped? Yes — use the open-source library with local providers like Ollama (LLM + embeddings) and a local vector store (Qdrant, FAISS, pgvector). No data leaves your machine.
Q: How is a memory different from just logging the chat? A memory is a deduplicated, self-contained fact that's been reconciled against what's already known (added, updated, or skipped as a duplicate) and made searchable by meaning. Raw logs aren't searchable by meaning and grow without bound.
Q: How do I keep one user's memories from leaking to another?
Always scope with user_id (and/or agent_id/run_id). Searches only return memories matching the scope in filters. Two users with different user_ids never see each other's memories.
Q: What's the difference between delete_all() and reset()?
delete_all() removes memories for a specific scope (a user, agent, or run). reset() wipes the entire store and recreates it. Both are irreversible.
Q: Can I attach my own metadata and filter on it?
Yes. Pass metadata={...} on add(), then filter with operators (eq, in, gte, contains, etc.) and boolean logic (AND/OR/NOT) on search().
Q: Does search use embeddings only? The open-source library uses hybrid retrieval: semantic similarity + BM25 keyword matching + entity boosting, combined into one score. Optionally a reranker sharpens the top results.
Q: What is "procedural memory"?
A special memory type for agents: a detailed, verbatim-preserving summary of an agent's step-by-step execution history. Create it with memory_type="procedural_memory" and an agent_id.
Q: Can I use Mem0 from the command line or inside a coding agent?
Yes. The mem0 CLI provides every operation, auto-detects coding-agent environments, and offers a --json mode for scripting.
Q: Is there a way to add memory to my chatbot without rewriting it?
Use the LLM proxy (mem0.proxy.main.Mem0). Swap your chat.completions.create(...) call for the proxy's and pass a user_id — memory retrieval and storage become automatic.
Q: How do I see why the agent "knows" something?
Call history(memory_id) to see the full add/update/delete trail of any memory.
Q: Does Mem0 collect telemetry?
The open-source library and self-hosted server send anonymous usage telemetry by default. Opt out by setting MEM0_TELEMETRY=false.
19. Reference
Memory operations (at a glance)
| Operation | Open Source (Memory) |
Platform (MemoryClient) |
|---|---|---|
| Add | add(messages, user_id=...) |
add(messages, user_id=...) |
| Search | search(q, filters={...}) |
search(q, filters={...}) |
| Get one | get(memory_id) |
get(memory_id) |
| Get all | get_all(filters={...}) |
get_all(filters={...}) |
| Update | update(memory_id, data) |
update(memory_id, text=...) |
| Delete | delete(memory_id) |
delete(memory_id, delete_linked=...) |
| Delete all | delete_all(user_id=...) |
delete_all(user_id=...) |
| History | history(memory_id) |
history(memory_id) |
| Reset | reset() |
reset() |
| Batch update/delete | — | batch_update([...]), batch_delete([...]) |
| Entities | — | users(), delete_users(...) |
| Exports / summary | — | create_memory_export(...), get_summary(...) |
| Feedback | — | feedback(memory_id, "POSITIVE") |
Key environment variables (user-facing)
| Variable | Used by | Purpose |
|---|---|---|
MEM0_API_KEY |
Platform client, CLI | Authenticate with the Mem0 Platform |
OPENAI_API_KEY |
Open source (default) | Default LLM + embeddings |
MEM0_DIR |
Open source | Working dir for history DB (default ~/.mem0) |
MEM0_TELEMETRY |
Open source, server | Set false to opt out of anonymous telemetry |
MEM0_BASE_URL |
CLI | Override the API base URL |
MEM0_USER_ID / MEM0_AGENT_ID / MEM0_APP_ID / MEM0_RUN_ID |
CLI | Default scope IDs |
NO_COLOR |
CLI | Disable colored output |
Packages
| Package | Ecosystem | What it is |
|---|---|---|
mem0ai |
PyPI | Python library (Platform + Open Source) |
mem0ai |
npm | TypeScript SDK (mem0ai = Platform, mem0ai/oss = Open Source) |
@mem0/cli |
npm | The mem0 command-line tool |
@mem0/vercel-ai-provider |
npm | Vercel AI SDK provider |
@mem0/community |
npm | Community integrations (LangChain) |
@mem0/openclaw-mem0 |
npm | OpenClaw memory backend |
Supported providers (open source)
- LLMs: OpenAI, Anthropic, Gemini, Groq, Together, AWS Bedrock, Azure OpenAI, DeepSeek, MiniMax, xAI, Sarvam, Ollama, LM Studio, vLLM, LiteLLM, LangChain.
- Embedders: OpenAI, Ollama, Hugging Face, Azure OpenAI, Gemini, Vertex AI, Together, LM Studio, AWS Bedrock, FastEmbed, LangChain.
- Vector stores: Qdrant, Chroma, pgvector, Milvus, Pinecone, Redis, Valkey, Weaviate, FAISS, Elasticsearch, OpenSearch, MongoDB, Supabase, Azure AI Search, Databricks, Vertex AI Vector Search, Upstash, S3 Vectors, Cassandra, Baidu, Neptune Analytics, Turbopuffer, Azure MySQL.
- Rerankers: Cohere, sentence-transformer, ZeroEntropy, LLM-based, Hugging Face.
Where to go next
- Configuration reference, deployment, security, internals → the companion Mem0 Admin Guide.
- Runnable examples → the
examples/directory in the repository. - Official documentation → docs.mem0.ai.