CodeWords raises $9M seed round
BlogResources

How to avoid context bleeding in multi-user WhatsApp bots

Context bleeding in multi-user WhatsApp bots can expose user data. Learn what causes it and how to prevent it with per-user session isolation.

Rebecca PearsonRebecca Pearson5 min read
How to avoid context bleeding in multi-user WhatsApp bots

There's a category of WhatsApp bot failure that's more alarming than a missed message or a wrong answer. Context bleeding — where one user's data influences the responses another user receives — can expose personal information, create deeply confusing conversations, and in some cases, constitute a privacy breach.

It happens more often than most builders expect, and it's almost always a preventable architectural mistake.

TL;DR

  • Context bleeding occurs when conversation memory isn't isolated per user — one person's messages leak into another person's session.
  • The root cause is shared memory without proper namespacing, common in naive implementations that store conversation history in a single global variable or shared cache.
  • CodeWords uses Redis keyed by phone number to ensure every user's context is completely isolated — it handles this automatically, with no configuration required.

What context bleeding actually looks like

Imagine your WhatsApp bot is handling an appointment booking. User A — let's call her Sarah — has just told the bot she's coming in for a dental checkup on Thursday at 2pm. The bot confirms her booking.

Now User B — let's call him James — messages the bot with "Can I change my appointment?" The bot, if it's bleeding context from Sarah's session, might respond: "Of course, I can help you change your Thursday 2pm appointment." James has never made an appointment. He's confused. And Sarah's appointment details have just been disclosed to a stranger.

This is context bleeding in its most obvious form. In subtler cases, it might look like:

  • A bot referring to a user by the wrong name
  • Pricing or product details from one conversation appearing in another
  • A follow-up question about a topic the current user never raised
  • A bot offering to "continue where we left off" in a conversation that belongs to someone else

Why it happens

Context bleeding happens when the conversation memory layer doesn't properly isolate sessions per user.

In a simple single-user bot, there's no problem — there's only one conversation. But the moment you're handling multiple concurrent users, you need each user's history to live in its own isolated space.

The most common causes of context bleeding are:

Global in-memory variables: storing conversation history in a single server-side variable (like a Python dictionary without a user key) means all users share the same history buffer. The first user to message after a restart gets a clean state. Everyone after that inherits whatever was there before.

Shared cache without namespacing: using a caching layer (Redis, Memcached, etc.) but storing conversation history under a generic key like conversation_history rather than a user-specific key like conversation:+447911123456. Any user that hits the cache gets the same stored context.

Session handoff without cleanup: in setups where conversations are passed between handlers or queued for processing, if the previous conversation isn't cleared before the next one starts, fragments of it can persist into the new session.

Stateless AI APIs called with shared context: if you're constructing the messages array to send to an AI model and accidentally include messages from a different user's history, the model will treat them as part of the current conversation.

The right approach: isolation by phone number

The correct architecture for a multi-user WhatsApp bot is simple in principle: every piece of conversation state must be keyed to a unique user identifier.

In WhatsApp, the natural identifier is the user's phone number. Every inbound message includes the sender's phone number, which is unique, persistent, and available without any additional authentication.

The pattern looks like this:

  1. Inbound message arrives from +447911123456
  2. Look up conversation history for key conversation:+447911123456
  3. Append the new message to that user's history
  4. Send the history to the AI model and get a response
  5. Append the response to the same user-specific history
  6. Save the updated history back to conversation:+447911123456

Every read and write is scoped to that specific phone number. There's no way for Sarah's history to appear in James's session because they're stored under completely different keys.

TTL expiry: the second layer of protection

Even with proper namespacing, conversation memory accumulates over time. A user who last messaged you six months ago still has a stale history in memory. If they message again, the bot will pick up an outdated conversation that's no longer relevant — which can feel strange to the user and, in the worst case, replay information they've since updated.

TTL (time-to-live) expiry solves this. By setting a TTL on each conversation key, you ensure that stale contexts automatically expire and users start fresh after a defined period of inactivity.

Sensible TTL defaults:

  • 1–2 hours: appropriate for transactional bots (bookings, orders, support queries) where each interaction is self-contained
  • 24 hours: suitable for ongoing sales or onboarding conversations that might span a day
  • 7 days: appropriate for relationship-oriented bots where you want the AI to remember context across multiple sessions in a week

Longer TTLs carry higher privacy risk (more data sitting in memory) and higher cost (more tokens on each request). Match the TTL to what your use case actually needs.

Namespace isolation: going further

For businesses running multiple bots on the same infrastructure — say, a dental bot and a separate accounting bot — you should namespace your memory keys beyond just the phone number.

A key like dental:conversation:+447911123456 ensures that even if the same user contacts both of your bots, their contexts stay completely separate. The dental bot won't have access to anything they discussed with the accounting bot.

This matters both for privacy and for bot quality. A bot that has irrelevant context from a different product or service in its history will produce confused, off-topic responses.

How CodeWords handles this automatically

If you're building on CodeWords, context bleeding is handled for you. CodeWords uses Redis for per-user conversation memory, with each session keyed by the user's phone number by default. You don't need to configure this — it's built into the platform.

Key properties of CodeWords' memory architecture:

  • Automatic phone-number keying: every conversation is stored under the sender's phone number from the first message
  • Default TTL of 1–2 hours: sessions expire naturally, keeping memory fresh and preventing stale context accumulation
  • No shared state between users: there's no global conversation buffer — each user's history is fully isolated
  • Consistent across connection methods: the same isolation applies whether you're using Business API or Personal Device connection

This means you can build a WhatsApp bot handling hundreds of concurrent conversations without ever worrying about one user's data leaking into another's session.

What to check if you're building outside CodeWords

If you're building a WhatsApp bot with a custom stack — using a framework like n8n or a raw API integration — here's a quick checklist to verify you're not bleeding context:

  • Is every conversation stored under a user-specific key (phone number or equivalent)?
  • Does your cache or database enforce namespace isolation?
  • Have you set a TTL on stored conversations?
  • If you're running multiple bots, are they namespaced separately?
  • When you construct the message array for the AI model, are you filtering strictly to the current user's history?

If you can answer yes to all of these, you're in good shape. If any answer is "I'm not sure," that's worth investigating before you put the bot in front of real users.

Building with confidence

Context bleeding is one of those problems that doesn't show up in simple testing — a single-user test will never reveal it. It only emerges at scale, when multiple users are interacting concurrently, and by then you may already have exposed data you didn't mean to.

The right time to address it is in the architecture phase, before you have users. And if you're building on CodeWords, Cody (the AI automation assistant) sets up proper memory isolation as part of every bot build — you get the protection without having to think about the plumbing.

Start building on CodeWords and let Cody handle the memory architecture for you.

Get started today

Your first agent is free to build.

Describe what you need. Cody handles the build, the connections, and the deployment.