Skip to content

User Context

Scope data to tenants and users with context filters and row-level security.


In most production applications, multiple tenants (organisations, teams, or users) share the same database. Without proper scoping, a query from one tenant could return another tenant’s data.

User context solves this by attaching context to every conversation. Inconvo uses this context to automatically apply filters on every query, ensuring data isolation at the query level.

Context fields are defined in your agent’s configuration. Each field represents a key that will be passed when creating a conversation. Common examples include:

  • organisationId — scope data to a specific organisation
  • teamId — scope data to a team within an organisation
  • userId — scope data to a specific user

You can define context fields in the Inconvo dashboard under your agent’s Configure page, or via the CLI.

Context filters are set on a per-table basis, where a mapping is made between a column in the table and a key in the context object.

For example, if you have a table orders with a column organisation_id which is your tenant identifier, set the following context filter on the orders table:

WHERE orders.organisation_id = userContext.organisationId;

Passing userContext when creating conversations

Section titled “Passing userContext when creating conversations”

When creating a conversation via the API, pass the userContext object in the request body. The values you provide will be used to evaluate context filters on every query within that conversation.

import Inconvo from "@inconvoai/node";
const inconvo = new Inconvo({
apiKey: process.env.INCONVO_API_KEY,
});
const conversation = await inconvo.agents.conversations.create(
process.env.INCONVO_AGENT_ID,
{
userIdentifier: "user_123",
userContext: {
organisationId: 1,
},
},
);

Within this conversation, data returned from the orders table will be scoped to the organisation with an id of 1:

WHERE orders.organisation_id = 1;

The simplest pattern — set a context filter on every queryable table with the tenant identifier:

WHERE orders.organisation_id = userContext.organisationId;
WHERE users.organisation_id = userContext.organisationId;
WHERE products.organisation_id = userContext.organisationId;

Combine multiple context fields for finer-grained access:

-- Organisation-level tables
WHERE orders.organisation_id = userContext.organisationId;
-- Team-level tables
WHERE projects.team_id = userContext.teamId;

For tables that should only return rows belonging to a specific user:

WHERE notes.user_id = userContext.userId;