Cherry Studio token usage: blank costs, estimates, and billing
Find a request in desktop Usage → Requests, distinguish provider-reported costs from local estimates and unknown amounts, and check token or image billing against provider records. Covers the released v2.1.6 interface, per-image pricing merged into main, currencies, historical prices, and missing records.
Contents

Cherry Studio’s token usage statistics can show a blank or a dash in the Requests Cost column even after an image has been generated. That does not mean the request was free, and a displayed amount is not automatically your provider’s bill. Find the specific record under Settings → Usage → Requests, then check where the amount came from, the billing unit, and what the provider actually charged to establish whether a price is missing, the client cannot estimate the cost, or the two systems are counting different calls.
Keep the request and billing records you already have; you do not need to generate images repeatedly just to make Cost display a number. The interface and calculation details below are based on the official release’s source code and merged changes. They explain how the client records costs, without establishing that a particular provider, model, and account combination has been verified through live requests.
Check the version: per-image pricing has merged, but is not yet in the latest release
As of 2026-10-17, the official latest release is still v2.1.6; PR #21892, which adds an editor for per-image prices, was merged into main on that date. main is the development branch. A merged change does not establish that the official version you have installed includes it. See the official release record and the per-image pricing PR.
On 2026-10-16, codeBennyLaw reported in issue #21870 that Windows v2.1.6 exposed only per-million-token price fields and showed dashes for some image requests’ costs. That report describes the user’s environment; it does not mean that all image models are free to use. The issue has since been closed with the PR, but your installed version still determines which interface you have.
| The interface you actually have | What it supports | What to do |
|---|---|---|
| The v2.1.6 model price editor | Input, output, and cache token rates, including pricing tiers; no per-image price field | Check token prices for models billed by tokens; compare requests billed by image directly with provider records |
| A build containing PR #21892, with Price unit and Image price actually visible | A price per generated image | Confirm that the provider bills per image, then enter the appropriate rate and verify a new request |
| A newer or customized build with a different interface | Capabilities depend on that build | Check its documentation and actual fields before using a screenshot from another version as configuration guidance |
This comparison follows the v2.1.6 price editor and the price editor with the merged change. The instructions use English interface labels to help you find the controls; the labels vary with the client’s language.
Find the same request in Requests
Match the request before comparing amounts. Have the client version, the provider configuration used at the time, the exact model ID, and usage or charge records from the same provider account ready. Matching model display names alone do not establish that you used the same model or billing route.
- Open Settings → Usage → Requests, select a time range covering the request, and locate it by Date.
- Check the model name on each row and the provider name beneath it. Source identifies the assistant, session, or feature that made the call; it does not identify the source of the cost.
- Note the date and time, Tokens, Cost, and currency. If the record is missing, switch back to sorting by Date, check the time range, and use the option to load more at the bottom of the list. Sorting by Cost also filters by the selected currency, which can exclude records with missing costs.
- Keep the provider’s records for the same period. The client’s record date comes from the call’s completion time. The provider may use a different accounting timestamp or time zone, so choose a window that covers the whole request.
You can check these fields and their display behavior in the official Requests table source and the record-writing logic.
If the entire list is empty, first check the time range, loading, and whether the call has finished. If only Cost is missing, continue with the pricing and cost-source checks. These situations call for different actions; reinstalling the app or clearing its history does not establish whether the provider charged you.
Three cost states, none identified by the Source column
Where an amount comes from matters more than how precise it looks. The official recording logic first attempts to accept a provider-reported cost that meets its conditions. Otherwise, it estimates the amount using the pricing snapshot captured for the request. If neither is available, the cost remains empty. See the cost-recording logic.
| State in the record | What it means | How to use it when checking charges |
|---|---|---|
costSource is provider | The client accepted a cost returned by the provider; the provider capability declaration, amount, and currency conditions must be satisfied | Treat it as cost information carried by that response, and still compare it with charges recorded in the provider account |
costSource is computed | The client calculated the amount from usage and the pricing snapshot captured at the time | Use it for estimates and trends, and check whether the local rates match your actual account pricing |
| Cost is missing and the cost source is empty | No usable provider amount was available, and local calculation could not be completed | The amount is unknown; check the provider’s actual charge and do not substitute zero |
v2.1.6 displays a missing Cost as -; the checked main version uses Unable to estimate in English. The current Requests table has no separate costSource column or cost-source tooltip. Do not interpret Source as that field or infer the source from an amount alone. If the interface does not explicitly identify the source, treat it as unspecified. See the main table and the English interface text.
A cost field in the provider’s response does not guarantee that the client will accept it. Acceptance also depends on conditions such as whether the provider declares that it reports actual costs and whether the currency can be determined. You do not need to modify internal records to investigate this; checking the actual charge still requires the provider account. See the official explanation of cost semantics.
Token estimates: check the unit, then the usage categories
Tokens in Requests is a usage total; you cannot simply multiply it by one universal rate. computed means that the amount was calculated locally, not that the token count was also estimated locally. The official total function uses totalTokens first, and only falls back to adding the available input and output counts when that total is absent. If both are unknown, it preserves a missing value. See the token total definition.
Go to Settings → Model Provider → select the provider → the gear icon for the relevant model → More settings and find the pricing section. Check it against the current prices for that account, model, and billing tier:
- Input Price / Output Price are the input and output prices per million tokens. If the provider quotes a price per thousand tokens, convert it to a per-million rate before entering it; do not copy the number unchanged.
- Cache Read Price / Cache Write Price cover cache reads and writes separately. Leaving either field blank in the current editor falls back to that tier’s input rate. Entering 0 means that the local calculation uses a free rate; blank does not mean free.
- Pricing tiers: when tiers depend on input length, the client selects a tier using the request’s complete input count and applies it to the whole call. It does not charge successive portions at successive tier rates. If necessary usage or rates are missing, the estimate may remain empty.
See the price editor for the fields and save behavior, and the cost semantics documentation for the calculation.
Keep category counts and rates together in your reconciliation record: uncached input × input rate + cache reads × read rate + cache writes × write rate + output × output rate, converting each term consistently to the per-million-token basis. If the total input already includes cached tokens, split those categories first so that cached tokens are not also charged as regular input in your calculation. Likewise, do not add reasoning tokens again if they are already included in output. If you cannot obtain category counts, mark them as unknown; do not turn the total Tokens value into a supposedly exact bill.
Check the currency too: in the price editor reviewed here, $ means USD and ¥ means CNY, not JPY. Changing the symbol does not convert the rate using an exchange rate. If your top-up receipt or bank statement uses your local currency while the model prices are in US dollars, first check the dollar-denominated call costs, then separately check the top-up exchange rate and fees. Do not add amounts in different currencies together. See the currency mapping and price-saving code.
After editing a price, move focus out of the field and reopen the same model to confirm that the value was saved. Check whether the provider configuration also includes a price multiplier or time-based pricing rules, so that an actual rate already containing a multiplier is not multiplied again. Historical requests retain their original pricing snapshots; changing today’s price does not automatically reprice old requests. See the multiplier and time-based rule code and the request-time pricing snapshot.
Blank image costs: distinguish per-request and per-image billing
Billing per request, per image, and per image token are different arrangements. One request can return several images. A flat fee per request cannot simply be entered as a per-image rate or placed in Input Price or Output Price.
v2.1.6 already has underlying per-image calculation logic, but the desktop price editor has no corresponding input. A local image estimate requires a runtime pricing snapshot containing perImage with unit set to image, plus an imageCount supplied by the call. Token prices alone, or a unit of pixel, are insufficient. See the conditions for image cost calculation.
If your build actually displays the new controls and the provider explicitly bills per generated image, configure the price as follows:
- In the pricing section for the same provider and model, change Price unit to Image.
- Enter the price per image in the appropriate currency in Image price. Move focus out of the field, then reopen the model to confirm that it was saved.
- Leave the price blank if it is unknown. Enter 0 only when the rate really is zero; entering zero manually changes the local display, not whether the provider charges you.
- The selector only changes which rate you are editing. Both token and image rates are retained. It does not add a flat fee per request or solve pixel-based or image-token cost estimation.
- Check one new generation made after the price change. Once you have the result, record the actual image count, request time, and new Cost, then compare them with the provider’s records. The local calculation should use “generated image count × per-image price effective at request time,” accounting for any applicable provider multiplier or time-based rules. A new verification request may still incur a charge; prefer a generation you already need to make.
These steps follow the new price editor and the price-saving function. If those controls are absent, reconcile against the provider’s actual records first. Configure the rate once the official version you install explicitly includes the feature.
Even after you enter an image price, a new request can still have a missing cost. Check whether it used another model configuration, whether the image count is missing, whether currency information is incomplete, and whether the actual billing arrangement differs from per-image pricing. The official custom image-job path records imageCount from the number of image URLs returned, so the number of files successfully downloaded to your computer is not an interchangeable count. That behavior also does not establish how every provider bills images. See the image-job recording code.
Compare actual provider charges and save a record that explains differences
Start with one completed request; it is easier to explain than a difference between two monthly totals. Use the same provider account, and record the key label or group if it helps distinguish usage. Keep full API keys out of screenshots and support requests.
| What to save | Cherry Studio | Provider |
|---|---|---|
| Identity | Client version, provider configuration, model display name and corresponding exact ID | Actual account, model ID, applicable pricing tier |
| Time | Request completion time and local time zone | Accounting timestamp, time zone, and a window covering the same call |
| Quantity | Visible Tokens; the number of images actually returned by the image task | Input, output, cache, and other usage categories; billable request or image count |
| Amount | Cost exactly as displayed, currency, and any missing values | Actual charge, currency, and visible refunds or adjustments |
| Association | The session or feature responsible for the request | Request or billing identifier supplied by the provider |
If both sides explicitly expose the same provider request ID, use it to match records first. Otherwise, reconcile using the account, model, time window, and quantities together. Cherry Studio’s internal request identifiers follow their own naming conventions; do not assume they are identical to provider IDs. See the official record structure.
If you already use BetterToken, follow the official usage guidance to view current usage and charge history in the dashboard, then check the model, time, status, and tokens using the fields actually available on the page.
When amounts differ, work through these checks in order:
- The quantities differ: check whether other tools use the same account or whether one operation produced several calls. SDK retries the client cannot observe may not appear in Requests, so the two lists do not necessarily have a one-to-one correspondence.
- Quantities match but amounts differ: check the model, per-image/per-request/token unit, cache rules, tiers, currency, multipliers, and actual account rates, then inspect the old pricing snapshot from when the request ran.
- The provider charged you but the client’s Cost is blank: preserve the blank value and record “client unable to estimate; provider charged” alongside the actual amount. Do not replace the missing value with zero.
- The client has no record or shows a failure, but the provider has a record: first establish the provider’s completion, charging, and refund rules. Supply the time, model, and provider request identifier with sensitive details removed; do not immediately retry a batch of requests to reproduce the issue.
The official documentation describes these usage records as analytics captured on a best-effort basis. Unobserved retries, failures, and historical migration records can all affect quantity comparisons. Use the provider’s records to establish actual charges and ask the provider to explain unclear entries; a blank Cost cell cannot supply that explanation. See the record coverage and limitations.
What a completed check looks like
You should have records from both sides for the same request and be able to explain three things: which model and billing unit were used, whether the client amount has an identified source or is estimated/unknown, and what the provider ultimately charged and why it differs. If you changed a local price, use a new request to confirm that the setting was saved and the calculation works. Preserve the original values of old requests; do not expect historical records to be recalculated.
Start now with one existing image request: note the version, model, time, actual image count, Cost, and provider charge. Once you can explain that request, expand the time range for your totals. If you cannot, take the missing fields and the corresponding request to the provider or the client project for investigation.