Supermemory provides two complementary filtering mechanisms that work independently or together to help you find exactly what you need.
How Filtering Works
Supermemory uses two types of filters for different purposes:
Container Tags Organize memories into isolated spaces by user, project, or workspace
Metadata Filtering Query memories by custom properties like category, status, or date
Both filtering types can be used:
Independently - Use container tags alone OR metadata filters alone
Together - Combine both for precise filtering (most common)
Think of it as: [Container Tags] → [Your Memories] ← [Metadata Filters]
Container tags create isolated memory spaces. They’re perfect for multi-tenant applications, user profiles, and project organization.
Exact matching : Arrays must match exactly. A memory tagged with ["user_123", "project_ai"] will NOT match a search for just ["user_123"]
Isolation : Each container tag combination creates a separate knowledge graph
Naming patterns : Use consistent patterns like user_{id}, project_{id}, or org_{id}_team_{id}
Basic Usage
// Search within a user's memories
const results = await client . search . documents ({
q: "machine learning notes" ,
containerTags: [ "user_123" ],
limit: 10
});
// Search within a project
const projectResults = await client . search . documents ({
q: "requirements" ,
containerTags: [ "project_ai" ],
limit: 10
});
# Search within a user's memories
results = client.search.documents(
q = "machine learning notes" ,
container_tags = [ "user_123" ],
limit = 10
)
# Search within a project
project_results = client.search.documents(
q = "requirements" ,
container_tags = [ "project_ai" ],
limit = 10
)
# Search within a user's memories
curl -X POST "https://api.supermemory.ai/v3/search" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"q": "machine learning notes",
"containerTags": ["user_123"],
"limit": 10
}'
Container Tag Patterns
Best Practice : Use single container tags when possible. Multi-tag arrays require exact matching, which can be restrictive.
Recommended Patterns
User isolation: user_{userId}
Project grouping: project_{projectId}
Workspace separation: workspace_{workspaceId}
Hierarchical: org_{orgId}_team_{teamId}
Temporal: user_{userId}_2024_q1
API Differences
Endpoint Field Name Type Example /v3/searchcontainerTagsArray ["user_123"]/v4/searchcontainerTagString "user_123"/v3/documents/listcontainerTagsArray ["user_123"]
Metadata filters let you query memories by any custom property. They use SQL-like AND/OR logic with explicit grouping.
Filter Structure
All metadata filters must be wrapped in AND or OR arrays:
// ✅ Correct - wrapped in AND array
filters : {
AND : [
{ key: "category" , value: "tech" , negate: false }
]
}
// ❌ Wrong - not wrapped
filters : {
key : "category" , value : "tech" , negate : false
}
Why Explicit Grouping?
Without explicit grouping, this SQL query is ambiguous:
category = 'tech' OR status = 'published' AND priority = 'high'
Our structure forces clarity:
// Clear: (category = 'tech') OR (status = 'published' AND priority = 'high')
{
OR : [
{ key: "category" , value: "tech" },
{ AND: [
{ key: "status" , value: "published" },
{ key: "priority" , value: "high" }
]}
]
}
// Single condition
const results = await client . search . documents ({
q: "neural networks" ,
filters: {
AND: [
{ key: "category" , value: "ai" , negate: false }
]
},
limit: 10
});
// Multiple AND conditions
const filtered = await client . search . documents ({
q: "research" ,
filters: {
AND: [
{ key: "category" , value: "science" , negate: false },
{ key: "status" , value: "published" , negate: false },
{ key: "year" , value: "2024" , negate: false }
]
},
limit: 10
});
# Single condition
results = client.search.documents(
q = "neural networks" ,
filters = {
"AND" : [
{ "key" : "category" , "value" : "ai" , "negate" : False }
]
},
limit = 10
)
# Multiple AND conditions
filtered = client.search.documents(
q = "research" ,
filters = {
"AND" : [
{ "key" : "category" , "value" : "science" , "negate" : False },
{ "key" : "status" , "value" : "published" , "negate" : False },
{ "key" : "year" , "value" : "2024" , "negate" : False }
]
},
limit = 10
)
# Single condition
curl -X POST "https://api.supermemory.ai/v3/search" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"q": "neural networks",
"filters": {
"AND": [
{"key": "category", "value": "ai", "negate": false}
]
},
"limit": 10
}'
Filter Types in Detail
Supermemory supports four filter types, each designed for specific use cases.
1. String Equality (Default)
Exact string matching with optional case-insensitive comparison.
Basic
Case-Insensitive
Negation
// Case-sensitive exact match (default)
{
key : "status" ,
value : "Published" ,
negate : false
}
// Matches "published", "Published", "PUBLISHED"
{
key : "status" ,
value : "PUBLISHED" ,
ignoreCase : true ,
negate : false
}
// Exclude specific status
{
key : "status" ,
value : "draft" ,
negate : true
}
2. String Contains
Search for substrings within text fields.
Basic
Case-Insensitive
Exclusion
// Find all documents containing "machine learning"
{
filterType : "string_contains" ,
key : "description" ,
value : "machine learning" ,
negate : false
}
// Case-insensitive substring search
{
filterType : "string_contains" ,
key : "title" ,
value : "NEURAL" ,
ignoreCase : true ,
negate : false
}
// Exclude documents containing "deprecated"
{
filterType : "string_contains" ,
key : "content" ,
value : "deprecated" ,
negate : true
}
3. Numeric Comparisons
Filter by numeric values with comparison operators.
Basic Operators
With Negation
// Greater than or equal
{
filterType : "numeric" ,
key : "score" ,
value : "80" ,
numericOperator : ">=" ,
negate : false
}
// Less than
{
filterType : "numeric" ,
key : "readingTime" ,
value : "10" ,
numericOperator : "<" ,
negate : false
}
// NOT equal to 5 (becomes !=)
{
filterType : "numeric" ,
key : "priority" ,
value : "5" ,
numericOperator : "=" ,
negate : true
}
// NOT less than 80 (becomes >=)
{
filterType : "numeric" ,
key : "score" ,
value : "80" ,
numericOperator : "<" ,
negate : true
}
Numeric Negation Mapping :
When using negate: true with numeric filters, operators are reversed:
< → >=
<= → >
> → <=
>= → <
= → !=
4. Array Contains
Check if an array field contains a specific value.
Basic
Exclusion
Multiple Checks
// Find documents with specific participant
{
filterType : "array_contains" ,
key : "participants" ,
value : "john.doe" ,
negate : false
}
// Exclude documents with specific tag
{
filterType : "array_contains" ,
key : "tags" ,
value : "archived" ,
negate : true
}
// Must have both participants (use AND)
{
AND : [
{
filterType: "array_contains" ,
key: "participants" ,
value: "project.manager"
},
{
filterType: "array_contains" ,
key: "participants" ,
value: "lead.developer"
}
]
}
Common Patterns
Ready-to-use filtering patterns for common scenarios.
User-Specific Content with Category
const results = await client . search . documents ({
q: "project updates" ,
containerTags: [ "user_123" ],
filters: {
AND: [
{ key: "category" , value: "work" , negate: false },
{ key: "visibility" , value: "private" , negate: false }
]
},
limit: 10
});
results = client.search.documents(
q = "project updates" ,
container_tags = [ "user_123" ],
filters = {
"AND" : [
{ "key" : "category" , "value" : "work" , "negate" : False },
{ "key" : "visibility" , "value" : "private" , "negate" : False }
]
},
limit = 10
)
Recent High-Priority Content
const results = await client . search . documents ({
q: "important tasks" ,
filters: {
AND: [
{
filterType: "numeric" ,
key: "priority" ,
value: "7" ,
numericOperator: ">=" ,
negate: false
},
{
filterType: "numeric" ,
key: "created_timestamp" ,
value: "1704067200" , // 2024-01-01
numericOperator: ">=" ,
negate: false
}
]
},
limit: 20
});
results = client.search.documents(
q = "important tasks" ,
filters = {
"AND" : [
{
"filterType" : "numeric" ,
"key" : "priority" ,
"value" : "7" ,
"numericOperator" : ">=" ,
"negate" : False
},
{
"filterType" : "numeric" ,
"key" : "created_timestamp" ,
"value" : "1704067200" , # 2024-01-01
"numericOperator" : ">=" ,
"negate" : False
}
]
},
limit = 20
)
Team Collaboration Filter
const results = await client . search . documents ({
q: "meeting notes" ,
containerTags: [ "project_alpha" ],
filters: {
AND: [
{
OR: [
{
filterType: "array_contains" ,
key: "participants" ,
value: "alice"
},
{
filterType: "array_contains" ,
key: "participants" ,
value: "bob"
}
]
},
{
key: "type" ,
value: "meeting" ,
negate: false
}
]
},
limit: 15
});
results = client.search.documents(
q = "meeting notes" ,
container_tags = [ "project_alpha" ],
filters = {
"AND" : [
{
"OR" : [
{
"filterType" : "array_contains" ,
"key" : "participants" ,
"value" : "alice"
},
{
"filterType" : "array_contains" ,
"key" : "participants" ,
"value" : "bob"
}
]
},
{
"key" : "type" ,
"value" : "meeting" ,
"negate" : False
}
]
},
limit = 15
)
Exclude Drafts and Deprecated Content
const results = await client . search . documents ({
q: "documentation" ,
filters: {
AND: [
{
key: "status" ,
value: "draft" ,
negate: true // Exclude drafts
},
{
filterType: "string_contains" ,
key: "content" ,
value: "deprecated" ,
negate: true // Exclude deprecated
},
{
filterType: "array_contains" ,
key: "tags" ,
value: "archived" ,
negate: true // Exclude archived
}
]
},
limit: 10
});
results = client.search.documents(
q = "documentation" ,
filters = {
"AND" : [
{
"key" : "status" ,
"value" : "draft" ,
"negate" : True # Exclude drafts
},
{
"filterType" : "string_contains" ,
"key" : "content" ,
"value" : "deprecated" ,
"negate" : True # Exclude deprecated
},
{
"filterType" : "array_contains" ,
"key" : "tags" ,
"value" : "archived" ,
"negate" : True # Exclude archived
}
]
},
limit = 10
)
API-Specific Notes
Different endpoints have slightly different requirements:
Endpoint Container Tag Field Type Filter Format Notes /v3/searchcontainerTagsArray JSON object Document search /v4/searchcontainerTagString JSON object Memory search /v3/documents/listcontainerTagsArray JSON string Must use JSON.stringify()
List API Special Requirement : The /v3/documents/list endpoint requires filters as a JSON string:// ✅ Correct for List API
filters : JSON . stringify ({ AND: [ ... ] })
// ❌ Wrong for List API (but correct for Search API)
filters : { AND : [ ... ] }
Most real-world applications combine both filtering types for precise control.
Example: User’s Work Documents from 2024
const results = await client . search . documents ({
q: "quarterly report" ,
containerTags: [ "user_123" ], // User isolation
filters: {
AND: [
{ key: "category" , value: "work" },
{ key: "type" , value: "report" },
{
filterType: "numeric" ,
key: "year" ,
value: "2024" ,
numericOperator: "="
}
]
},
limit: 10
});
results = client.search.documents(
q = "quarterly report" ,
container_tags = [ "user_123" ], # User isolation
filters = {
"AND" : [
{ "key" : "category" , "value" : "work" },
{ "key" : "type" , "value" : "report" },
{
"filterType" : "numeric" ,
"key" : "year" ,
"value" : "2024" ,
"numericOperator" : "="
}
]
},
limit = 10
)
Example: Project’s Active High-Priority Tasks
const results = await client . search . documents ({
q: "implementation" ,
containerTags: [ "project_alpha" ], // Project isolation
filters: {
AND: [
{
key: "status" ,
value: "completed" ,
negate: true // Not completed
},
{
filterType: "numeric" ,
key: "priority" ,
value: "7" ,
numericOperator: ">=" ,
negate: false
},
{
filterType: "array_contains" ,
key: "assignees" ,
value: "current_user"
}
]
},
limit: 20
});
results = client.search.documents(
q = "implementation" ,
container_tags = [ "project_alpha" ], # Project isolation
filters = {
"AND" : [
{
"key" : "status" ,
"value" : "completed" ,
"negate" : True # Not completed
},
{
"filterType" : "numeric" ,
"key" : "priority" ,
"value" : "7" ,
"numericOperator" : ">=" ,
"negate" : False
},
{
"filterType" : "array_contains" ,
"key" : "assignees" ,
"value" : "current_user"
}
]
},
limit = 20
)
Document-Specific Search
Search within a single large document using the docId parameter:
// Search within a specific book or manual
const results = await client . search . documents ({
q: "neural architecture" ,
docId: "doc_textbook_ml_2024" ,
limit: 20
});
# Search within a specific book or manual
results = client.search.documents(
q = "neural architecture" ,
doc_id = "doc_textbook_ml_2024" ,
limit = 20
)
Use this for:
Large textbooks or manuals
Multi-chapter books
Long podcast transcripts
Course materials
Validation & Limits
Pattern : /^[a-zA-Z0-9_.-]+$/
Allowed : Letters, numbers, underscore, hyphen, dot
Max length : 64 characters
No spaces or special characters
Valid vs Invalid Keys
// ✅ Valid keys
"user_email"
"created-date"
"version.number"
"priority_level_2"
// ❌ Invalid keys
"user email" // Spaces not allowed
"created@date" // @ not allowed
"priority!" // ! not allowed
"very_long_key_name_that_exceeds_64_characters_limit" // Too long
Query Complexity Limits
Maximum conditions : 200 per query
Maximum nesting depth : 8 levels
Container tag arrays : Must match exactly
Troubleshooting
No Results Returned
Problem : Container tags must match exactly as arrays.Solution : Verify the exact array structure. ["user_123"] ≠ ["user_123", "project_1"]
Wrong metadata key casing
Problem : Keys are case-sensitive by default.Solution : Check exact key spelling and casing, or use ignoreCase: true for values.
Problem : Using negate: true when you meant false.Solution : Review your negate values. false = include, true = exclude.
Validation Errors
Invalid metadata key format
Error : “Invalid metadata key: contains unsafe characters”Solution : Remove spaces, special characters. Use only alphanumeric, underscore, hyphen, dot.
Error : “Invalid filter structure”Solution : Ensure all conditions are wrapped in AND or OR arrays.
Error : “Invalid filter format”Solution : For /v3/documents/list, use JSON.stringify() on the filter object.
Problem : Complex nested OR conditions with many branches.Solution : Simplify logic, reduce nesting, or split into multiple queries.
Hitting complexity limits
Problem : “Query exceeds maximum complexity”Solution : Reduce conditions (max 200) or nesting depth (max 8).