Skip to main content
Nora runs a travel service. When she stored all memories in one bucket, a recruiter’s nut allergy accidentally appeared in a traveler’s dinner reservation. Let’s fix this by properly separating memories for different users, agents, and applications.
Time to complete: ~15 minutes · Languages: Python

Setup

from mem0 import MemoryClient

client = MemoryClient(api_key="m0-...")
Grab an API key from the Mem0 dashboard to get started.

Store and Retrieve Scoped Memories

Let’s start by storing Cam’s travel preferences and retrieving them:
cam_messages = [
    {"role": "user", "content": "I'm Cam. Keep in mind I avoid shellfish and prefer boutique hotels."},
    {"role": "assistant", "content": "Noted! I'll use those preferences in future itineraries."}
]

result = client.add(
    cam_messages,
    user_id="traveler_cam",
    agent_id="travel_planner",
    run_id="tokyo-2025-weekend",
    app_id="concierge_app",
    version="v2"
)
The memory is now stored. Let’s retrieve those memories with the same identifiers:
user_scope = {
    "AND": [
        {"user_id": "traveler_cam"},
        {"app_id": "concierge_app"},
        {"run_id": "tokyo-2025-weekend"}
    ]
}
user_memories = client.search("Any dietary restrictions?", filters=user_scope)
print(user_memories)

agent_scope = {
    "AND": [
        {"agent_id": "travel_planner"},
        {"app_id": "concierge_app"}
    ]
}
agent_memories = client.search("Any dietary restrictions?", filters=agent_scope)
print(agent_memories)
Output:
{'results': [{'memory': 'avoids shellfish and prefers boutique hotels', ...}]}
{'results': [{'memory': 'avoids shellfish and prefers boutique hotels', ...}]}
Memories can be written with several identifiers, but each search resolves one entity boundary at a time. Run separate queries for user and agent scopes—just like above—rather than combining both in a single filter.

When Memories Leak

When Nora adds a chef agent, Cam’s travel preferences leak into food recommendations:
chef_filters = {"AND": [{"user_id": "traveler_cam"}]}

collision = client.search("What should I cook?", filters=chef_filters)
print(collision)
Output:
['avoids shellfish and prefers boutique hotels', 'prefers Kyoto kaiseki dining experiences']
The travel preferences appear because we only filtered by user_id. The chef agent shouldn’t see hotel preferences.

Fix the Leak with Proper Filters

First, let’s add a memory specifically for the chef agent:
chef_memory = [
    {"role": "user", "content": "I'd like to try some authentic Kyoto cuisine."},
    {"role": "assistant", "content": "I'll remember that you prefer Kyoto kaiseki dining experiences."}
]

client.add(
    chef_memory,
    user_id="traveler_cam",
    agent_id="chef_recommender",
    run_id="menu-planning-2025-04",
    app_id="concierge_app",
    version="v2"
)
Now search within the chef’s scope:
safe_filters = {
    "AND": [
        {"agent_id": "chef_recommender"},
        {"app_id": "concierge_app"},
        {"run_id": "menu-planning-2025-04"}
    ]
}

chef_memories = client.search("Any food alerts?", filters=safe_filters)
print(chef_memories)
Output:
{'results': [{'memory': 'prefers Kyoto kaiseki dining experiences', ...}]}
Now the chef agent only sees its own food preferences. The hotel preferences stay with the travel agent.

Separate Apps with app_id

Nora white-labels her travel service for a sports brand. Use app_id to keep enterprise data separate:
enterprise_filters = {
    "AND": [
        {"app_id": "sports_brand_portal"},
        {"user_id": "*"},
        {"agent_id": "*"}
    ]
}

page = client.get_all(filters=enterprise_filters, page=1, page_size=10)
print([row["user_id"] for row in page["results"]])
Output:
['athlete_jane', 'coach_mike', 'team_admin']
Wildcards ("*" ) only match non-null values. Make sure you write memories with explicit app_id values.
Need a deeper tour of AND vs OR, nested filters, or wildcard tricks? Check the Memory Filters v2 guide for full examples you can copy into this flow.
When the sports brand offboards, delete all their data:
client.delete_all(app_id="sports_brand_portal")
Output:
{'message': 'Memories deleted successfully!'}

Production Patterns

# Nightly audits - check all data for an app
def audit_app(app_id: str):
    filters = {"AND": [{"app_id": app_id}, {"user_id": "*"}, {"agent_id": "*"}]}
    return client.get_all(filters=filters, page=1, page_size=50)

# Session cleanup - delete temporary conversations
def close_ticket(ticket_id: str, user_id: str):
    client.delete_all(user_id=user_id, run_id=ticket_id)

# Compliance exports - get all data for one tenant
export = client.get_memory_export(filters={"AND": [{"app_id": "sports_brand_portal"}]})

Complete Example

Putting it all together - here’s how to properly scope memories:
# Store memories with all identifiers
client.add(
    [{"role": "user", "content": "I need a hotel near the conference center."}],
    user_id="exec_123",
    agent_id="booking_assistant",
    app_id="enterprise_portal",
    run_id="trip-2025-03",
    version="v2"
)

# Retrieve with the same scope
filters = {
    "AND": [
        {"user_id": "exec_123"},
        {"app_id": "enterprise_portal"},
        {"run_id": "trip-2025-03"}
    ]
}

# Alternative: Use wildcards if you're not sure about some fields
# filters = {
#     "AND": [
#         {"user_id": "exec_123"},
#         {"agent_id": "*"},  # Match any agent
#         {"app_id": "enterprise_portal"},
#         {"run_id": "*"}      # Match any run
#     ]
# }

results = client.search("Hotels near conference", filters=filters)

# Debug: Print the filter you're using
print(f"Searching with filters: {filters}")

# If no results, try a broader search to see what's stored
if not results["results"]:
    print("No results found! Trying broader search...")
    broader = client.get_all(filters={"user_id": "exec_123"})
    print(broader)

print(results["results"][0]["memory"])
Output:
I need a hotel near the conference center.

When to Use Each Identifier

IdentifierWhen to UseExample Values
user_idIndividual preferences that persist across all interactionscam_traveler, sarah_exec, team_alpha
agent_idDifferent AI roles need separate contexttravel_agent, concierge, customer_support
app_idWhite-label deployments or separate productstravel_app_ios, enterprise_portal, partner_integration
run_idTemporary sessions that should be isolatedsupport_ticket_9234, chat_session_456, booking_flow_789

Troubleshooting Common Issues

My search returns empty results!

Problem: Using AND with exact matches but some fields might be null. Solution:
# If this returns nothing:
filters = {"AND": [{"user_id": "u1"}, {"agent_id": "a1"}]}

# Try using wildcards:
filters = {"AND": [{"user_id": "u1"}, {"agent_id": "*"}]}

# Or don't include fields you don't need:
filters = {"AND": [{"user_id": "u1"}]}

OR gives results but AND doesn’t

This confirms you have a field mismatch. The memory exists but some identifier values don’t match exactly. Always check what’s actually stored:
# Get all memories for the user to see the actual field values
all_mems = client.get_all(filters={"user_id": "your_user_id"})
print(json.dumps(all_mems, indent=2))

Best Practices

  1. Use consistent identifier formats
    # Good: consistent patterns
    user_id = "cam_traveler"
    agent_id = "travel_agent_v1"
    app_id = "nora_concierge_app"
    run_id = "tokyo_trip_2025_03"
    
    # Avoid: mixed patterns
    # user_id = "123", agent_id = "agent2", app_id = "app"
    
  2. Print filters when debugging
    filters = {"AND": [{"user_id": "cam", "agent_id": "chef"}]}
    print(f"Searching with filters: {filters}")  # Helps catch typos
    
  3. Clean up temporary sessions
    # After a support ticket closes
    client.delete_all(user_id="customer_123", run_id="ticket_456")
    

Summary

You learned how to:
  • Store memories with proper entity scoping using user_id, agent_id, app_id, and run_id
  • Prevent memory leaks between different agents and applications
  • Clean up data for specific tenants or sessions
  • Use wildcards to query across scoped memories

Next Steps