Handling workout sync tickets

5 min read · 887 words · 6 revisions · Updated Sep 5, 2026

This is how to answer a ticket about workouts not appearing, appearing twice, or disappearing. It assumes you can read the tenant database.

## "I logged a workout and it is not there"

Almost always a sync that has not completed rather than data that is gone. The apps log locally first and sync afterwards, deliberately: a set has to persist in under 100ms and a network round trip cannot promise that.

Ask, in this order:

# **Is the phone online now?** The app queues offline and drains on reconnect. A member on airplane mode has the session, it just has not left the device. # **Did they force-quit during the session?** The draft persists after every set change, so it should resume. If it did not, that is a real bug and worth an engineering ticket with the device and OS version. # **Are they looking at the right day?** The log date is the member's LOCAL day, taken from the client. Somebody who trained at 00:30 sees it under that date, not the previous one.

Check the server side with:

SELECT id, client_uuid, log_date, status, total_sets, created_at FROM workout_sessions WHERE user_id = ? ORDER BY started_at DESC LIMIT 10;

A row with status = 'in_progress' and an old started_at is a session the member never finished. That is not a defect; the app will still show it and they can complete or discard it.

## "The same workout is in there twice"

This should not happen, and if it does it is worth escalating rather than deleting one by hand.

Sessions are keyed on (user_id, client_uuid) with a UNIQUE index, so a replayed sync updates in place. Two rows means two different UUIDs, which means either two genuinely separate sessions or a client that minted a second UUID for one workout.

Workouts read back from Apple Health or Health Connect are keyed on (user_id, external_uid), also UNIQUE, so a session Loopa wrote out and then read back in cannot land twice.

SELECT id, client_uuid, external_uid, source, started_at, ended_at, total_sets FROM workout_sessions WHERE user_id = ? AND log_date = ?;

If the two rows have different sources - one loopa and one healthkit - the member logged in Loopa and a watch recorded the same session independently. Deleting the platform-sourced one is the right fix, and it is worth an engineering note so the time-window dedupe can be tightened.

## "My calories burned doubled"

A completed session is mirrored into the daily activity ledger so the dashboard, the reports and the challenge snapshots see it. The mirror's id is stored on the session, and a re-finalised session **updates** that mirror rather than adding a second one.

If a member's burn looks doubled, check whether the day carries two activity sessions for one workout:

SELECT id, activity_session_id, log_date, energy_kcal FROM workout_sessions WHERE user_id = ? AND log_date = ?;

A session with activity_session_id IS NULL that nevertheless has a mirror on the day is the shape to escalate.

## "Why does it say my calories are estimated?"

Because they are, unless the health platform reported measured active energy for that session. Loopa estimates from the exercise's MET value, the member's body weight and the session's elapsed time. That is an average over a population applied to one person, and it is labeled rather than presented as a measurement.

This is also why **eating back exercise calories is off by default**. Both sides of the estimate are noisy and they compound, so a member's daily calorie target does not move when they log a session. The preference is carried on the training preferences record and is off unless it has been set through the API; there is no member-facing control for it in the apps or in the browser today, so a ticket asking where to turn it on has the right answer of "it is already off, and off is the default".

## Free versus Premium

**Training is Premium, whole.** Logging a session is part of what a member pays for, and the same tier applies on the phone and in the browser.

**Premium:** saving a session, the exercise library, custom exercises, reading your own history, personal records, routines and folders, programs and the training calendar, progressive overload suggestions, the volume and strength analytics, coach comments and replies, and CSV export.

**Free, and neither of these is a feature:**

* **Deleting a session.** A member whose subscription has lapsed still owns what they wrote and must be able to take it out. * **Reporting a comment.** Flagging content that was shown to you is a safety function.

So a member on [Loopa Basic](/know/handling-tier-and-ai-allowance-tickets) who opens **Workouts** is offered the upgrade rather than the logger. That is the gate doing its job, not a defect. On the API it arrives as **402** with {"error":"premium_required","feature":"workouts"}, and both apps turn that into the purchase sheet.

Everything else on Loopa Basic is untouched: food, weight, water, vitals, micronutrients, manually logged activity and bringing a history in from another tracker are all free. If a member says the free tracker stopped taking a walk or a meal, that is worth escalating; being asked to subscribe to save a set is not.

Contributors:
Last edited by mobieus · Family meal sharing tickets: the conditions behind the share button and the Share with family? switch, reading a "logged but not shared" report back to a member, sharing a saved meal without logging it, and what to escalate
Created Aug 22, 2026
Was this article helpful?