Guides / Use cases
Health, fitness and coaching
For coaching, fitness and wellness apps: a coach that remembers each client's goals, setbacks and what worked, so every check-in builds on the last one. Recall stores the check-ins, learns about the client in the background and gives your coaching model the right memory. The data is about people's health, so this guide spends as much time on consent and deletion as on code.
What memory adds
Without memory, every check-in starts with "what are your goals?". With it, the coach follows the client's plan:
| Without memory | With Recall | |
|---|---|---|
| Week 1, intake form | Goal: a 10 km race in March. Trains on weekday mornings. Knee injury last year, cleared to run. | |
| Week 3, check-in | "Good to hear from you. What are you training for?" | "Two missed runs, but you kept your Sunday 5 km. Shall we move Thursday's run to the morning, when you usually train?" |
| Week 6, a sore knee | "Add hill sprints this week to build speed." | "Let's keep it flat and easy this week, given your knee. An easy week got you back on track in week 4." |
Recall does not give the advice. Your model and your coaching content do; Recall supplies what this client said and did before. It is not a medical device: do not use it for diagnosis or treatment decisions.
How to model it
| In your app | In Recall | Why |
|---|---|---|
| Your app, or each gym or clinic you sell to | Workspace, e.g. coach-app | A business customer's clients stay apart from everyone else's and can be deleted together. |
| A client | Peer client-3087 | A pseudonymous id from your own system. Recall learns about the client from what they write. |
| Your coach bot | Peer coach, with observeMe: false | Recall does not learn from the coach's own lines, only reads them as context, so they cost less. |
| A check-in (a daily log, a weekly chat) | Session, e.g. checkin-71204 | Context and summaries per check-in, and one place to delete a conversation from. |
| Answers from an intake form | Conclusions you write with conclusions.create | The client typed them; no model needs to interpret them. |
| Goals, progress, setbacks, what worked | Conclusions learned from check-ins, and the peer card | Learned in the background. A goal that changes is closed and replaced, not duplicated. |
If human coaches also message clients, make each coach a peer with observeMe: false too, so what Recall learns stays about the client.
Build it
Install the SDK (npm install @recall-memory/sdk or pip install recall-mem) and set RECALL_API_KEY. Call Recall from your server. Create the client, the coach and a session per check-in.
import { Recall } from "@recall-memory/sdk";
const recall = new Recall({ workspaceId: "coach-app" });
const client = recall.peer("client-3087");
// The coach is your app, so Recall learns about the client, not from the coach's own lines.
const coach = recall.peer("coach", { configuration: { observeMe: false } });
// One session per check-in.
const checkin = recall.session("checkin-71204", { peers: [client, coach] });
from pydantic import BaseModel
from recall_memory import PeerConfig, Recall
recall = Recall(workspace_id="coach-app")
client = recall.peer("client-3087")
# The coach is your app, so Recall learns about the client, not from the coach's own lines.
coach = recall.peer("coach", configuration=PeerConfig(observe_me=False))
# One session per check-in.
checkin = recall.session("checkin-71204", peers=[client, coach])
Intake answers: write them as facts. What the client entered in a form needs no interpretation, so conclusions.create stores each answer as a fact about the client, searchable at once. Write only the fields the client agreed to share, and keep anything safety-critical, such as an injury or a heart condition, in your own records too, where your app shows it every time.
// What the client typed into your intake form is already a fact: write it directly. It is
// searchable at once, with no model in between. Store only what coaching needs, with consent.
await client.conclusions.create([
"Goal: run a 10 km race in March.",
"Trains on weekday mornings, before work.",
"Knee injury last year; cleared to run by their physiotherapist.",
]);
# What the client typed into your intake form is already a fact: write it directly. It is
# searchable at once, with no model in between. Store only what coaching needs, with consent.
client.conclusions.create(
[
{"content": "Goal: run a 10 km race in March."},
{"content": "Trains on weekday mornings, before work."},
{"content": "Knee injury last year; cleared to run by their physiotherapist."},
]
)
Every check-in message: one request. turn stores the message and returns the context for the coach's reply in the same round trip: the intake facts, what Recall learned from earlier check-ins and a summary of older turns. It uses no model, so it is fast and included in the price.
// Each client message: store it and get back what the coach should know, in one request.
const { context } = await checkin.turn(
[client.message("Missed two runs this week, work was brutal. Did my Sunday 5 km though.")],
{ peerTarget: client, tokens: 2000 },
);
const prompt = context.toOpenAI(coach); // intake facts and past check-ins, then this one
// Your model writes the coach's reply from `prompt`; store it with the check-in.
await checkin.addMessages([
coach.message("Sunday counts. Shall we move Thursday's run to the morning too?"),
]);
# Each client message: store it and get back what the coach should know, in one request.
result = checkin.turn(
[client.message("Missed two runs this week, work was brutal. Did my Sunday 5 km though.")],
peer_target=client,
tokens=2000,
)
prompt = result.context.to_openai(assistant=coach) # intake facts and past check-ins first
# Your model writes the coach's reply from `prompt`; store it with the check-in.
checkin.add_messages(
[coach.message("Sunday counts. Shall we move Thursday's run to the morning too?")]
)
The weekly review, as JSON. Ask in plain language with responseFormat, and your app gets fields it can turn into next week's plan. In TypeScript pass a JSON Schema or { jsonSchema, parse }; in Python a Pydantic class, or a JSON-schema dict (you then get the JSON text). It is one model call of a few seconds: run it from a weekly job and store the result, not while the client waits.
// Once a week: a review as JSON that your app turns into next week's plan.
// (waitForIdle is for this demo; a weekly job runs long after learning has finished.)
await recall.waitForIdle();
type WeeklyReview = { progress: string[]; setbacks: string[]; worked: string[]; focus: string };
const list = { type: "array", items: { type: "string" } };
const review = await client.chat(
"Review this client's last week against their goals: progress, setbacks, what worked, " +
"and the one thing to focus on next week.",
{
reasoningLevel: "low",
responseFormat: {
jsonSchema: {
type: "object",
properties: { progress: list, setbacks: list, worked: list, focus: { type: "string" } },
required: ["progress", "setbacks", "worked", "focus"],
},
parse: (data: unknown) => data as WeeklyReview, // or a zod schema's parse
},
},
);
# Once a week: a review as JSON that your app turns into next week's plan.
# (wait_for_idle is for this demo; a weekly job runs long after learning has finished.)
recall.wait_for_idle()
class WeeklyReview(BaseModel):
progress: list[str]
setbacks: list[str]
worked: list[str]
focus: str
review = client.chat(
"Review this client's last week against their goals: progress, setbacks, what worked, "
"and the one thing to focus on next week.",
reasoning_level="low",
response_format=WeeklyReview,
)
Show clients what the coach remembers. Clients should be able to see what is stored about them and remove it. The dashboard's memory explorer is for you and your team, not for clients; build their page from the conclusions list, with a forget button per fact. The conclusion routes need a workspace key, so serve the page from your backend, never with a key in the browser or app. The list includes facts that later changed, not only current ones, which is the honest answer to "what do you hold about me?"; for a short current profile use the peer card (getCard(), get_card()). Deleting a fact does not delete the messages it came from: to remove those as well, delete the check-in.
// A "what my coach remembers" page for the client, served by your backend: these routes need a
// workspace key. The list includes facts that have since changed, not only current ones.
const page = await client.conclusions.list({ size: 50 });
const remembered = page.items.map((c) => ({ id: c.id, fact: c.content, learned: c.createdAt }));
// The client taps "forget" next to a fact:
const tapped = remembered[0]!.id;
await client.conclusions.delete(tapped);
# A "what my coach remembers" page for the client, served by your backend: these routes need a
# workspace key. The list includes facts that have since changed, not only current ones.
page = client.conclusions.list(size=50)
remembered = [{"id": c.id, "fact": c.content, "learned": c.created_at} for c in page.items]
# The client taps "forget" next to a fact:
tapped = remembered[0]["id"]
client.conclusions.delete(tapped)
A client leaves. Delete their check-ins (the coach's replies quote them), then the client: client.delete() erases their messages, every fact and card about them, and cached answers.
// The client deletes their account: their check-ins first (the coach's replies quote them),
// then the client and everything learned about them.
for (const s of await (await client.sessions()).toArray()) await s.delete();
const removed = await client.delete();
# The client deletes their account: their check-ins first (the coach's replies quote them),
# then the client and everything learned about them.
for s in list(client.sessions()):
s.delete()
removed = client.delete()
Settings that matter
| Setting | Use |
|---|---|
observeMe: false on the coach | Recall learns about the client only. The coach's lines are read as context, not learned from, so they cost less. |
conclusions.create | Intake answers, and corrections the client makes on their "what my coach remembers" page: delete the wrong fact, write the right one. |
Message configuration: { reasoning: { enabled: false } } | Keep a message in the check-in without learning facts from it, for example text pasted from a report that the coach should read once, not remember. |
Workspace reasoning.customInstructions | Steer what is learned, for example: "Record training goals, progress, setbacks and what helped. Do not record diagnoses, medication or test results." It is an instruction to the model that learns, not a filter. |
responseFormat | JSON for the weekly review. The root must be an object; allOf, not and conditional keywords are not supported. |
reasoningLevel | low (the default) for the weekly review, minimal for quick checks. See Reasoning levels and models. |
Cost and speed
Measured from Europe against the hosted API (Frankfurt), October 2026: a turn or context call took 0.3 to 0.7 seconds, a search about 0.9 seconds, and a question at minimal or low 2 to 4.5 seconds. Learning happens in the background and does not hold up the check-in.
Context, search, storage and summaries are included. You pay for learning, $1.75 per million message tokens with every message counting as at least 50, and for questions. Intake facts you write yourself are not messages, so no learning charge applies to them. A client with three check-ins a week (12 a month), each with 8 short messages from the client and 8 coach replies of about 60 tokens, and a weekly review:
| Item | Per month |
|---|---|
| Client messages: 12 × 8 × 50 tokens × $1.75 / 1M | $0.0084 |
| Coach replies, read but not learned from: 12 × 8 × 60 tokens × $1.75 / 1M | $0.0101 |
Weekly reviews at low: 4 × $0.005 | $0.0200 |
| Total | about $0.04 per client a month |
More in Cost and speed.
Privacy and forgetting
This is practical guidance, not legal advice. Check it against the law that applies to you, and see Privacy, consent and forgetting.
- Health data is special-category data. Under the GDPR, data about a person's health needs an explicit legal ground, usually their explicit consent: ask for it separately from your terms, in plain words, make it as easy to withdraw as to give, and check whether you need a data protection impact assessment. Our DPA asks you to send such data only where the law allows it, with the safeguards it requires.
- Tell clients what is stored. That the coach remembers their goals, progress, setbacks and what they say about their health and training; that the text is stored in the EU (Frankfurt) and processed by AI model providers in the US through OpenRouter, restricted to providers that do not collect the data; that it is not used to train models; and how to see and delete it.
- Store what coaching needs. Ask only for intake fields with a purpose, steer learning with a custom instruction, and leave out what you do not need.
- Let clients see it and delete it. Build the "what my coach remembers" page above, with a delete per fact and a delete-everything button. For an access request, add their check-ins (
session.messages()) to the facts; Export under Settings downloads everything your account stores. - Crisis content goes to your safety flow, not to memory. If a message suggests a risk to the client or someone else, your app's own safety flow should handle it: your moderation, a person, emergency resources. Check messages before you send them to Recall, and do not rely on Recall to notice.
- Not a medical device. Recall stores and recalls what was said. Its answers come from a model and can miss or misread a fact, so they must not be used to diagnose or to make treatment decisions.
Recall's own terms are in the privacy policy, the DPA and the security page.
Pitfalls
- Safety-critical facts only in memory. An injury, allergy or condition that must never be missed belongs in your own records as well, shown every time. Memory is learned by a model and can miss things.
- Consent buried in the terms. Health data needs explicit consent. Ask separately, say what is stored, and honour a withdrawal by deleting.
- A workspace key in the client's app. The conclusion routes need one, and it reaches every client. Serve the "what my coach remembers" page from your backend.
- Deleting a fact and expecting the words to go. The check-in that mentioned it stays. Delete the session too when the client wants the conversation gone.
- A review on every page load. A review takes seconds and every request is billed, cached or not. Run it on a schedule and store it.
- Expecting Recall to coach. Recall is memory, not the coaching model: bring your own model, your coaching content and your safety flow.
Next: Privacy, consent and forgetting · Tutoring and education