Global Price Parserby DontPayFull Labs

Read prices from any country,
the way people write them.

A TypeScript library for text and HTML. It returns the exact amount and the ISO currency, and tells you when the currency is a guess.

Free and open source · zero dependencies · no AI, no network

1.299,00 € reads as 1299.00 EUR, CHF 1'299.– as 1299.00 CHF, ₹1,23,456 as 123456.00 INR, 699,- on a Norwegian shop as 699.00 NOK, $25 on a Canadian shop as 25.00 CAD

What it reads

Prices as shops write them, and what the library returns. A question mark means the currency is the most likely one, not a certain one.

Price texts and how global-price-parser reads them
Written asReads asWhy
1.299,00 €1299.00 EURthe € symbol
CHF 1'299.–1299.00 CHFthe code; .– means no cents
12,-   3.999.-   5 990.-12.00   3999.00   5990.00whole amounts written with a dash
₹1,23,456123456.00 INRIndian digit grouping
59.900 د.ك59.900 KWDthe dinar has three decimals
٣٤٫٥٠ ر.س34.50 SARArabic-Indic digits
$25 on a .ca shop25.00 CADthe domain
$25 alone25.00 USD?most likely; could be CAD, AUD and 27 more
kr 299 on a Shopify shop set to NOK299.00 NOKthe shop's active currency
¥12,80012800 JPY?could be CNY; yen has no decimals
<del>$79.99</del> $59<sup>99</sup>59.99 USD?, and 79.99 marked struckthe old price is flagged; cents in <sup>
29,99 €/kg   199 lei/lună29.99 EUR per kg, 199.00 RON? per monthunits in every CLDR language; lei could be MDL
1.234 with no currency1234.00, or 1.234both readings are returned

Every row is the library's real output. It was also checked on 39 product pages from shops in 26 countries.

Install and use

TypeScript for Node.js 18 or later and browsers, plus Python and PHP ports that read the same data and give the same results.

How to install Global Price Parser in each language
JavaScript, TypeScriptnpm install global-price-parser
Python 3.9+pip install global-price-parser
PHP 8.1+composer require dontpayfull/global-price-parser
  1. Step 1: Read a price from text

    import { parsePrice, parsePrices } from 'global-price-parser'
    
    parsePrice('1.299,00 €')
    // { amount: '1299.00', currency: 'EUR', currencySure: true, ... }
    
    parsePrices('Abo: 9,99 €/Monat, Set ab 1.299,00 €')
    // 9.99 EUR per month, 1299.00 EUR
  2. Step 2: Or from HTML and the page around it

    // an HTML string
    parsePrice('<del>$79.99</del> <ins>$59<sup>99</sup></ins>')
    
    // a DOM element, in the browser or with jsdom
    parsePrice(document.querySelector('.product-price'))
    
    // what you know about the shop
    parsePrice('$25', { url: 'https://shop.example.ca/p/1' })
    parsePrice('kr 299', { country: 'NO' })

    With a DOM element it also reads the signals of its page. With a string, pass the page as { page: html }.

Every option and field is in the README. Python and PHP: Python README, PHP README.

How it picks the currency

The symbol next to the number always wins: 25 € is EUR on any page. Signals only choose between the currencies a symbol can mean, such as USD, CAD or AUD for $, or SEK, NOK, DKK or ISK for kr.

Currency signals in the order they count
1. Your options{ currency: 'CAD' }, { country: 'NO' }, { language: 'de-CH' }
2. Shop platformthe active currency in Shopify, BigCommerce, PrestaShop, Magento, VTEX, WooCommerce and Shopware
3. TrackingdataLayer ecommerce, gtag, Meta pixel, Klaviyo
4. Structured dataJSON-LD priceCurrency, microdata, og:price:currency
5. URL?currency=CAD
6. Country of the pageShopify or PrestaShop country, ?country=CA, the page's own hreflang, <html lang="en-CA">, /en-ca/ or /ca/fr/ in the path, the .ca domain
7. Nothing foundthe most common currency for the symbol, with currencySure: false

Some signals are left out on purpose because they mislead: the Shopify base currency, og:locale, <html lang> without a country, and domains like .co, .io or .ai. A language without a country in your options, like { language: 'en' }, only guesses. The result names the signal that decided in decidedBy.

Limits

  • A separator followed by exactly three digits groups thousands, unless the currency has three decimals: a fuel price like 1,799 €/l reads as 1799.00 EUR.
  • Accounting brackets are not read as negative: (15.00) is 15.00.
  • Plain text has no struck prices. In Was $59.99, now $39.99 the first price comes first; use HTML, or parsePrices and choose.
  • It does not run the page's JavaScript, convert currencies, or read amounts written in words.

Questions

Why not Intl.NumberFormat or a regex?

Intl.NumberFormat writes prices but cannot read them back. A regex like /[^0-9.]/g turns 1.299,00 € into 1.29900. Real pages mix both separators, local symbols and markup.

Why is the amount a string?

So that it stays exact and keeps the currency's decimals: "1299" for JPY, "1299.00" for EUR, "59.900" for KWD. The same amount is also there as a number, in value.

What does currencySure: false mean?

More than one currency was possible and nothing on the page decided. The currency returned is the most common one for that symbol; the others are in otherCurrencies.

Does it use AI or send data anywhere?

No. It is plain code with currency data from Unicode CLDR built in. It makes no network calls, and the same input always gives the same output.

I use price-parser in Python. Is this the same?

It covers the same ground, and adds HTML and the page signals above. It has a Python version too: pip install global-price-parser.

What is the license?

Apache-2.0, free for commercial use. If it helps you, a mention of DontPayFull is welcome. Issues and pull requests are welcome on GitHub.