Guides / Build well
Cost and speed
What Recall costs per user, per ticket or per player each month, how fast each call is, and how to spend less. Prices come from the price list and speeds from our own measurements, and every example shows its arithmetic, so you can redo it with your own numbers.
How pricing works
Recall runs on prepaid credit in US dollars, with no subscription; new accounts get $5. You pay for two things, learning from messages and answering questions. Everything else is included.
| What | Price | How it is counted |
|---|---|---|
| Learning from a message | $1.75 per 1M message tokens | Each message counts as at least 50 tokens. |
| A message read but not learned from | $1.75 per 1M tokens read | Messages from a peer with observeMe: false, or in a session or message with reasoning off. Only what Recall reads counts: at most 200 tokens when it reads the message as context, 600 for a summary, and no 50-token minimum. |
A question (chat) | $0.0008 to $0.25 | Per question, by reasoning level (below). An answer from empty memory is free. A cached answer is still billed as one question. |
Context and turn, search, storage, summaries, the night shift | Included | No charge per call. |
So a short message such as "Sounds good, book it" costs 50 × $1.75 / 1M = $0.0000875 to learn from, and a 400-token message 400 × $1.75 / 1M = $0.0007. A 30-token line from a bot you do not observe costs 30 × $1.75 / 1M = $0.0000525. Every stored message comes back with its tokenCount, so you can measure your own averages.
| Question level | Per question | Per 1,000 questions |
|---|---|---|
minimal | $0.0008 | $0.80 |
low (default) | $0.005 | $5 |
medium | $0.025 | $25 |
high | $0.05 | $50 |
max | $0.25 | $250 |
The price of a question is taken when the answer starts and given back if no answer comes, so a question never spends credit you do not have. When your credit runs out or you reach your monthly cap, questions answer 402 and learning pauses; messages are still stored. See Pricing.
Three monthly examples
A chat assistant with one daily user
Assumptions: 30 days. The user sends 20 messages a day, each shorter than 50 tokens, so each counts as 50. The assistant sends 20 replies a day of about 150 tokens; it has observeMe: false, so each reply counts at its length, under the 200-token cap. Every reply's prompt comes from turn. Your app asks two questions a day at low, for example to decide what to suggest.
| Item | Per month |
|---|---|
| User messages: 30 × 20 × 50 tokens × $1.75 / 1M | $0.0525 |
| Assistant replies, read not learned: 30 × 20 × 150 tokens × $1.75 / 1M | $0.1575 |
| Context for 600 replies | Included |
Questions at low: 30 × 2 × $0.005 | $0.30 |
| Total | $0.51 per user |
Without the questions, reading context instead, the same user costs $0.21 a month.
A support bot with 1,000 tickets a month
Assumptions: each ticket has 6 customer messages of about 60 tokens and 6 bot replies of about 120 tokens; the bot has observeMe: false. Every bot reply is built from context. When a ticket opens, the bot asks one question at low ("what has this customer had trouble with before?"). One ticket in ten goes to a human, with a handoff summary asked at medium.
| Item | Per month |
|---|---|
| Customer messages: 1,000 × 6 × 60 tokens × $1.75 / 1M | $0.63 |
| Bot replies, read not learned: 1,000 × 6 × 120 tokens × $1.75 / 1M | $1.26 |
| Context for 6,000 replies | Included |
Opening question at low: 1,000 × $0.005 | $5.00 |
Handoff summaries at medium: 100 × $0.025 | $2.50 |
| Total | $9.39, about $0.0094 per ticket |
Questions are 80% of this bill. Reading the customer's context when a ticket opens, instead of asking, brings it to $4.39.
A game with 10,000 weekly players
Assumptions: the same player as in Game NPCs, who plays about two hours a week: 200 lines of their own, each under 50 tokens so counted as 50; 200 NPC lines of about 30 tokens, from NPCs with observeMe: false; 20 game-logic questions at minimal. Every line of dialogue uses turn. A month is 4 weeks.
| Item | Per month |
|---|---|
| Player lines: 10,000 × 4 × 200 × 50 tokens × $1.75 / 1M | $700 |
| NPC lines, read not learned: 10,000 × 4 × 200 × 30 tokens × $1.75 / 1M | $420 |
| Context for 8,000,000 lines of dialogue | Included |
Questions at minimal: 10,000 × 4 × 20 × $0.0008 | $640 |
| Total | $1,760, or $0.176 per player |
How fast each call is, and when to use it
| Call | Measured | Price | Use it for |
|---|---|---|---|
turn or context | 0.3 to 0.7 s | Included | Every prompt: recent messages, a summary of older ones and what is known about the person, within a token budget. turn also stores the new message, in the same round trip. |
| Search | About 0.9 s | Included | Finding what was said, word for word: an order number, a quote to show as a source. |
Chat at minimal or low | 2 to 4.5 s | $0.0008 or $0.005 | An answer your code needs: a decision, a JSON field, a summary for a person. |
Chat at medium, high or max | Slower | $0.025 to $0.25 | Questions that need many facts or several steps. high and max search memory in several rounds. |
| Learning | In the background, usually within about 20 seconds | Per message | Nothing to call: it never holds up a request. |
Measured from Europe against the hosted API in Frankfurt, October 2026; from farther away, add your network round trip. To keep a product fast: build prompts with turn, one request per turn; ask questions before the user needs the answer, when a conversation or scene starts, or stream the answer (chatStream) so the first words show sooner; and never wait for learning in the request path, because context already includes the newest messages. Bursts beyond your rate limit answer 429 with Retry-After; the SDKs wait and retry for you. Reasoning levels and models covers choosing a level.
Ways to spend less
Do not learn from your own agents. With observeMe: false on an assistant, bot or NPC, its lines count only what Recall reads, with no 50-token minimum and at most 200 tokens as context, and memory fills with facts about your users rather than about your prompt. Short lines and long replies save the most.
Turn reasoning off where you only need context. A chat with a visitor who is not signed in, or a pasted log or document: set reasoning: { enabled: false } in the configuration of the session or of that one message.
import { Recall } from "@recall-memory/sdk";
const recall = new Recall({ workspaceId: "assistant-prod" });
const user = recall.peer("user-8412");
// Your prompt defines the assistant: Recall reads its replies but does not learn from them.
const assistant = recall.peer("assistant", { configuration: { observeMe: false } });
const chat = recall.session("chat-6120");
// A visitor who is not signed in: keep the chat as context, learn nothing from it.
const visitor = recall.peer("visitor-3b9e");
const noLearning = { configuration: { reasoning: { enabled: false } } };
const guest = recall.session("guest-3b9e", noLearning);
await guest.addMessages([visitor.message("Do you ship to Belgium?")]);
// The same setting on one message: stored for context, not learned from, like a pasted log.
await chat.addMessages([user.message("Error log: payment timed out (504)", noLearning)]);
from recall_memory import PeerConfig, Recall
recall = Recall(workspace_id="assistant-prod")
user = recall.peer("user-8412")
# Your prompt defines the assistant: Recall reads its replies but does not learn from them.
assistant = recall.peer("assistant", configuration=PeerConfig(observe_me=False))
chat = recall.session("chat-6120")
# A visitor who is not signed in: keep the chat as context, learn nothing from it.
visitor = recall.peer("visitor-3b9e")
no_learning = {"reasoning": {"enabled": False}}
guest = recall.session("guest-3b9e", configuration=no_learning)
guest.add_messages([visitor.message("Do you ship to Belgium?")])
# The same setting on one message: stored for context, not learned from, like a pasted log.
chat.add_messages(
[user.message("Error log: payment timed out (504)", configuration=no_learning)]
)
Read context instead of asking. If your model writes the reply anyway, context gives it what Recall knows, faster and at no charge.
Ask at the lowest level that answers well. minimal costs about a sixth of low; max costs 50 times low.
Keep answers instead of asking again. Recall caches answers until the memory behind them changes, but a cached answer is still billed. Keep the answer in your app for the conversation, and refresh it when a queue.empty webhook says learning for that session has finished.
// Every reply: one request stores the user's line and returns the prompt context.
// It makes no model call and is included in the price.
const { context } = await chat.turn(
[user.message("Book the hotel by Ghent station again, like last time.")],
{ peerTarget: user, tokens: 3000 },
);
const prompt = context.toOpenAI(assistant);
// Your model writes the reply from `prompt`; store it so the next context includes it.
await chat.addMessages([assistant.message("Happy to. Which dates?")]);
// Ask only when your code needs an answer, at the cheapest level that gives a good one, and
// keep it for the conversation instead of asking again on every turn.
await recall.waitForIdle(); // for this demo; real apps rarely wait for learning
const hotel = await user.chat("Which hotel did I stay at last time?", {
reasoningLevel: "minimal",
});
# Every reply: one request stores the user's line and returns the prompt context.
# It makes no model call and is included in the price.
result = chat.turn(
[user.message("Book the hotel by Ghent station again, like last time.")],
peer_target=user,
tokens=3000,
)
prompt = result.context.to_openai(assistant=assistant)
# Your model writes the reply from `prompt`; store it so the next context includes it.
chat.add_messages([assistant.message("Happy to. Which dates?")])
# Ask only when your code needs an answer, at the cheapest level that gives a good one, and
# keep it for the conversation instead of asking again on every turn.
recall.wait_for_idle() # for this demo; real apps rarely wait for learning
hotel = user.chat("Which hotel did I stay at last time?", reasoning_level="minimal")
Batch messages. Store a turn's messages in one call (turn, or addMessages with several), and store a streamed reply once it is complete, not chunk by chunk. If your users send bursts of short lines ("hi", "quick question", "about my order"), consider joining them into one message: the 50-token minimum applies to each message Recall learns from.
Set a monthly cap. Under Billing, set a monthly cap so a bug or a leaked key cannot spend more than you planned, and auto top-up so learning does not pause when credit runs low. The dashboard's Usage page shows charges per day.
Pitfalls
- Asking on every turn. A question at
lowper reply adds $0.005 and seconds to every turn. Read context instead and ask only when your code needs an answer. - Learning from your own bot. Leave
observeMeon for an assistant and Recall profiles your prompt, and every "Got it" counts as 50 tokens. - Storing streamed chunks as messages. Each chunk becomes a message. Store the reply once it is complete.
- Waiting for learning in the request path.
waitForIdleis for tests and scripts. In production read context, which includes the newest messages at once. maxby default. It costs 50 timeslowand is slower. Keep it for the questions that need it.- No cap on a public app. A retry loop or a leaked key can spend all your credit. Set a monthly cap before launch.