Prices
Every card on the site carries a price, and every list a total. Prices are written into the site at build time, in up to three currencies and from up to four stores.
The header’s Prices dropdown picks the store every price comes from, everywhere on the site: list pages, the index tiles, Quick Switch, and Combine Lists. A store names its currency, so this one control also switches currency.
Currencies
Section titled “Currencies”A currency is never picked on its own: every price store has exactly one (TCGplayer and Card Kingdom are USD, Cardmarket is EUR, Cardhoarder is TIX), and a site offers exactly its stores’ currencies. The default priceSources: ["tcgplayer"] offers USD only; TIX appears only when priceSources includes cardhoarder.
The --price-sources flag on build-site can narrow the stores for one build. It never adds a store priceSources does not enable, and a value naming only such stores is refused. Under serve --api the flag is refused outright, since the live server always offers the configured stores.
The header’s Prices dropdown lists each enabled store of an offered currency by name, with the USD stores (TCGplayer, Card Kingdom) together. With a single store, or an empty priceSources, it is hidden.
Switching to a store in another currency:
- Updates every displayed price
- Recalculates deck and section totals
- Recomputes collection prices with the card’s finish-specific price in the new currency
- Re-runs the “Lowest Price” toggle for the active currency and price store, updating images to match
- Relabels price bracket groups with the new currency symbol
The site opens on the configured defaultPriceSource when it offers that store, otherwise on the first store it offers.
A disclaimer below the header shows when prices were retrieved: “Prices accurate as of <date>”. Prices are fetched from Scryfall at build time.
Price stores
Section titled “Price stores”Prices on the public and admin sites come from the stores declared by the priceSources config key. Each store quotes in one currency:
| Store | Currency | Where the price comes from |
|---|---|---|
tcgplayer |
USD | Scryfall’s USD market price (TCGplayer). The default. |
cardmarket |
EUR | Scryfall’s EUR trend price (Cardmarket). |
cardkingdom |
USD | Card Kingdom’s Near Mint retail price, from the same feed sell mode uses. |
cardhoarder |
TIX | Scryfall’s MTGO tix price (Cardhoarder). |
The Prices dropdown
Section titled “The Prices dropdown”Picking a store in the header re-prices every card, total, sort, and grouping on the page and clears the price filter. The index tiles, Quick Switch, and Combine Lists rows follow it too: the build bakes each list’s totals for every store it offers, Card Kingdom included. The admin site has the same dropdown in its header, opening on the same configured store.
The store choice is part of the shareable view URL as prices=<store> (for example prices=cardkingdom or prices=cardmarket), so a link opens its recipient on that store, in that store’s currency. Only an explicit choice is written: the untouched default stays out of the URL, and so does the Card Kingdom default that sell mode applies (sell=1 reproduces it). An explicit TCGplayer pick inside sell mode is written, so a shared link can show “offer versus market price”. A store the recipient’s site does not offer falls back to one in the same currency, else its default. The choice survives navigation for the session, and a later site refresh never overrides it.
When both USD stores are enabled, a USD-store selector also appears inside the dialogs that show one card’s printings: the card modal’s Other Printings grid, the trade/edit printing picker, and the add-card dialog’s printing step. It is the same choice as the header’s: switching it in a dialog switches the page behind it, and vice versa. Each printing there is priced under the selected store. A printing sold in more than one finish lists its alternate finishes underneath its main price. The grid’s price sort follows the selected store too.
Card Kingdom prices never fall back
Section titled “Card Kingdom prices never fall back”Card Kingdom retail prices come from the same buylist quotes sell mode writes into the site, so they work on a fully static site. A printing Card Kingdom does not sell, or a non-English copy (their catalog is English-only), shows no price under this view. There is no TCGplayer fallback, so a Card Kingdom total is what these cards really cost at CK. An out-of-stock product keeps its listed price.
Printing dialogs follow the same rule. A build with the cardkingdom store enabled stores a Card Kingdom quote for every printing a list carries, in each finish, not just the printings its tiles display, so a static site can price the whole other-printings grid with no backend. Where there is a live backend (serve --api, or the admin site), printings the build never saw (anything the add-card dialog’s search turns up) are quoted on demand.
In sell mode, the spread (Buylist vs Price) compares Card Kingdom’s offer against the selected store’s price. Entering sell mode switches a USD view to Card Kingdom retail when that store is enabled; a EUR or TIX view keeps its store and currency, and the spread then compares against the default USD store. Switching the Prices dropdown to TCGplayer compares the offer against the market price instead. An explicit choice always wins. Leaving sell mode restores the default only if the default was in force.
Enabling Card Kingdom prices
Section titled “Enabling Card Kingdom prices”ritual config set priceSources tcgplayer cardkingdomEnabling cardkingdom makes build-site, serve --api, and admin want the Card Kingdom feed, exactly as site.sellMode does:
- Builds refresh the feed under the run’s
--refreshpolicy. - Servers refresh a day-old feed at startup.
- The buylist API routes open.
- The first ~70 MB download still has to be deliberate (for example
ritual sell --refresh auto, or the admin Refresh Cache page).
A build with no feed ships the site without Card Kingdom prices (every card shows unpriced under that view) and never fails over it. Sell mode stays a separate toggle.
Turning prices off entirely
Section titled “Turning prices off entirely”An empty priceSources array hides every price surface on both sites: per-card prices, page and section totals, the price sort, filter, and grouping, the card modal’s price rows, the Update Prices button, and the header’s Prices dropdown. Sell mode (buylist prices) and the CLI price command are unaffected.
ritual config set priceSources --remove tcgplayer # from the default, leaves []Which printing a card is priced at
Section titled “Which printing a card is priced at”A card line that names no printing (4 Lightning Bolt, not 4 Lightning Bolt (M10:146)) gets a representative printing from the build: among the five most recent printings that have a price, the newest that is not priced far above their median. The “Lowest Price” toggle swaps in a second pick, the cheapest printing of the card.
Both picks are made per store, with that store’s own prices over that store’s own catalog. Under Card Kingdom the representative is the newest printing CK sells, and the lowest price is the cheapest printing+finish CK sells (a foil counts, since Card Kingdom sells it as its own product). Switching the Prices selector therefore swaps the printing a name-only card displays, art and set included. A build that offers Card Kingdom prices stores both sets of picks, so the switch needs no rebuild.
The admin editors get the same picks from the admin API’s list-load routes, so an editor and the published page never disagree about which printing a line is. The picks are made when the list loads, so a card added mid-session has no Card Kingdom pick yet and uses its Scryfall pick until the next load.
Two things do not move:
- A line that names its printing displays and prices at that printing under every store. If Card Kingdom does not sell it, it reads as unpriced. Another printing is never substituted.
- A card Card Kingdom stocks no printing of keeps its Scryfall pick, so it still shows its art and text, with only the price reading as unavailable.
ritual price --source cardkingdom applies the same rule, so a deck priced on the CLI and on the site reads the same printings.
Update Prices (per page)
Section titled “Update Prices (per page)”Every deck, collection, and wanted-list page has an Update Prices button (also shown while editing) in the button group above the filter toolbar. It does nothing until pressed. Pressing it fetches current prices for that page’s cards from Scryfall in one batch and updates the displayed per-card prices and totals in place. Nothing is written to disk; the refresh lives only in the current browser tab. On a site backed by a live API, the refresh instead goes through the backend’s batch price endpoint, which updates its shared card cache server-side.
If a refresh only updates some cards (for example, a card Scryfall no longer returns by id), the remaining cards keep their older build-time price. When a page ends up with mixed price dates, a small expandable warning lists the cards whose prices are now older than the rest. Refreshing again so every card is covered clears it. The refreshed prices are shared with the card search in the public editor and the Trade Planner, so a card fetched once is reused without another request.
Missing prices
Section titled “Missing prices”When a card cannot be priced in the selected currency (a paper-only card has no TIX price, an MTGO-only card has no USD/EUR price), it is left out of price totals. A collapsible warning banner at the top of the deck page lists the cards with missing prices for the active currency, and updates when you switch currencies. Proxies and custom-art cards are not “missing”: they are priced at zero by rule and never appear in this banner.
On the index page (deck, collection, and wanted-list tiles), and in the Quick Switch and Combine Lists rows, a list with missing prices shows “$X.XX+ (N unpriced)” instead of the raw total: the + means the real total is at least that much. Deck tiles show only the ordinary total; the cheapest-printing figure lives behind the deck page’s “Lowest Price” toggle.
The ~ and + are for the eye: screen readers hear the total spelled out instead (“Estimated at least $X.XX, N cards have no price”), and hovering any qualified total shows the same wording as a tooltip.
Estimated totals
Section titled “Estimated totals”A deck or wanted-list total is prefixed “~” (approximately) when any card in it has no specific price: its line names no printing (so it is priced at the representative printing), or its printing has no price from the active store. This applies everywhere such a total appears: the index tiles, the Quick Switch and Combine Lists rows, the page total, the Filtered stat, section totals, and the combined and Find views. A total that is both an estimate and missing prices reads “~$X.XX+ (N unpriced)” (only where the + form appears, above). The index tiles and the Quick Switch and Combine Lists rows read figures baked at build time for every offered store, Card Kingdom included, so they match the page under whichever store is selected. Collections never show the ~, since every collection line pins its printing. Proxies and custom-art cards are an exact zero and never make a total an estimate.
Cards priced at zero
Section titled “Cards priced at zero”A proxy (a card whose effective labels include proxy) is not a real card, so the build prices it at 0 in every currency. It is left out of list totals and of the missing-price counts and banner, and it is never offered to a buyer in sell mode. Switching currency or pressing Update Prices cannot give it a price; the rule is applied in the browser too.
A card wearing custom art is treated the same way, since it is no longer the printing a price would be quoted for. Wherever a per-card price is shown (grid and list views, the card modal, the Trade Planner), such a card reads CUSTOM, and a proxy without custom art reads PROXY. A card that is both reads CUSTOM.
Ritual is unofficial Fan Content permitted under the Fan Content Policy. Not approved or endorsed by Wizards of the Coast. Portions of the materials used are property of Wizards of the Coast. ©Wizards of the Coast LLC.
Card data, images and symbols come from Scryfall, which is not affiliated with this project. Ritual is free software under the AGPL-3.0. License and attribution.