Skip to main content
A container tag is the primary way you organize and isolate memories in Supermemory. It’s a simple string identifier you attach to content when you add it — and that you pass back when you search, list, or update it. Think of a container tag as a namespace: every memory tagged with user_alex lives in its own isolated space, completely separate from memories tagged user_jordan. This is what makes Supermemory safe to use in multi-tenant applications — one user can never see another user’s memories unless you explicitly query across both tags.

Group

Bucket memories by user, project, agent, workspace, or any boundary that makes sense for your app.

Isolate

Each container tag maps to its own vector namespace, so search and retrieval never leak across boundaries.

How it works

When you add a memory with a container tag, Supermemory automatically creates a space for that tag (scoped to your organization) if one doesn’t already exist. You don’t need to provision anything ahead of time — the first write with a new tag creates the container, and subsequent writes reuse it.
// First call auto-creates the "user_alex" container
await client.add({
  content: "Alex prefers dark mode and concise answers",
  containerTag: "user_alex",
});

// Later, retrieve only Alex's memories
const results = await client.search.memories({
  q: "what are the user's UI preferences?",
  containerTag: "user_alex",
});
Under the hood, each container tag is hashed into a dedicated vector namespace. Embeddings, chunks, and memory entries for one tag are stored and searched independently of every other tag — there is no shared index to filter through, which is why isolation is strict rather than best-effort.
A container tag is an opaque identifier you choose. Supermemory does not parse meaning out of it — user_123, project_mobile, and org:acme:team:growth are all equally valid. Pick a convention that mirrors the access boundaries in your own application.

Naming rules

Container tags are validated on every request. A tag must:
  • Be 100 characters or less
  • Contain only alphanumeric characters, hyphens (-), underscores (_), and colons (:)
Matching pattern: ^[a-zA-Z0-9_:-]+$
// ✅ Valid
"user_123"
"project-mobile-app"
"org:acme:user:john"
"tenant_42_workspace_7"

// ❌ Invalid — spaces, slashes, and other symbols are rejected
"user 123"
"project/mobile"
"team@acme"
The colon is intentionally allowed so you can build hierarchical tags (for example org:acme:user:john) that encode several levels of structure in a single identifier.

containerTag vs containerTags

Supermemory’s current API uses a single containerTag string per request.
The plural containerTags array field is deprecated. It still works for backward compatibility on older (/v3) endpoints, but new integrations should use the singular containerTag string. The /v4 API only accepts containerTag.
API fieldTypeStatus
containerTagstring✅ Current — use this
containerTagsstring[]⚠️ Deprecated

Where container tags are used

The same tag flows through the entire lifecycle of a memory. Pass it consistently and your data stays neatly partitioned.
OperationBehavior
AddWrites the memory into the tag’s container (auto-creating the space).
SearchRestricts retrieval to the given tag’s namespace.
ListReturns only memories belonging to the tag(s).
Update / DeleteTargets the memory inside the specified tag’s container.
// Add
await client.add({ content: "Q1 planning notes", containerTag: "project_q1" });

// Search within the same container
await client.search.memories({ q: "planning", containerTag: "project_q1" });

// List everything in the container
await client.documents.list({ containerTags: ["project_q1"] });

Access control

Container tags are also an authorization boundary, not just an organizational one. Two mechanisms can restrict which tags a given caller may touch:
  • API key scopes — an API key can be limited to a specific set of container tags, with read or write permission per tag.
  • Member restrictions — an organization member can be granted access to only certain container tags.
When a request is restricted, Supermemory validates the requested tag against the caller’s allowed set:
  • Requesting a tag outside the allowed set returns 403 Forbidden.
  • A write (add/update/delete) to a read-only tag returns 403 Forbidden.
  • If no tag is supplied by a restricted caller, the request is automatically scoped to their allowed tag(s).
This means you can hand out an API key that is physically incapable of reading or writing another tenant’s data, enforced at the data layer rather than in your application code.

Per-container settings

Each container tag can carry its own configuration, independent of other tags in the same organization:
SettingPurpose
nameA human-friendly display name for the container.
entityContextA custom context prompt applied when processing documents in this container — useful for steering extraction and summarization per project or tenant.
await client.containerTags.update("project_research", {
  entityContext: "This project contains research papers about machine learning.",
});
Container tags can also be merged when you need to consolidate two buckets of memories into one.

Choosing a convention

Pick a tagging scheme that maps onto the isolation boundaries your application actually needs.
PatternExampleUse case
User isolationuser_{userId}Per-user memory in a consumer app
Project groupingproject_{projectId}Project- or workspace-scoped content
Agent scopingagent_{agentId}Separate long-term memory per AI agent
Hierarchicalorg:{orgId}:user:{userId}Multi-level, multi-tenant SaaS
Keep tags deterministic — derive them directly from IDs you already have (a user ID, a tenant ID) so you can always reconstruct the right tag at query time without a lookup.

Next steps

Organizing & Filtering

Combine container tags with metadata filters for precise retrieval.

Adding Memories

See container tags in action across the add API.