Skip to content
Kokai
Language
Sections of this page
Open the app

Guide

Which booking confirmation PDFs Kokai reads, and how

Kokai reads, on the device itself, with pdf.js and without AI or a server, the text of the first 6 pages of a booking PDF of up to 20 MB. It recognises 65 brands and 8 booking classes (accommodation, flight, train, bus, boat, activity, car and insurance), and looks for the booking reference, dates and times, holder, price and free cancellation by their labels in seven languages. It only fills in what’s empty and, for accommodation, adds its nights to the trip; it doesn’t read photos or scanned PDFs.

Reviewed on 18 min read

In a nutshell

Where it’s read
On your device, with Mozilla’s pdf.js. Without AI and without sending the file to any server.
Which part of the PDF
The text of the first 6 pages, in files of up to 20 MB.
Booking classes
8: accommodation, flight, train, bus, boat, activity, rental car and travel insurance.
Brands recognised
65, from Booking.com and Airbnb to Ryanair, Renfe, FlixBus, GetYourGuide or Europcar.
Label languages
Spanish, English, French, Italian, Portuguese, Catalan and German.
Currencies
37 ISO 4217 codes and 8 symbols (€, £, $, US$, ¥, R$, C$, A$).
What it doesn’t read
Photos and scanned PDFs (they have no text) and password-protected PDFs.
Only trip to the network
The address of a hotel that isn’t on your map, to OpenStreetMap’s Nominatim, to place it.

How it works: text, not image

A booking confirmation PDF almost always has real text inside: the kind you can select and copy. Kokai extracts it with pdf.js, Mozilla’s library (Apache-2.0 licence) that Firefox uses to display PDFs, and loads it only when you add a PDF. It all happens on the device:

  1. If the file is over 20 MB, it’s stored without being read.
  2. pdf.js extracts the text of the first 6 pages: confirmations put what matters at the top, and twenty pages of terms add nothing.
  3. Kokai rebuilds the lines: pdf.js returns pieces of text with their position, and a line ends when the next piece drops by more than half a letter’s height.
  4. The text is lowercased and stripped of accents to search for labels (“Número de confirmación” and “numero de confirmacion” are the same), but what’s found is cut from the original, so the booking reference keeps its capitals.
  5. It decides what it is and who it’s from, and looks for the details by their labels. There are no per-provider templates, which change every few months.
  6. If the class isn’t recognised and fewer than two details come out, it counts as not read: «No he encontrado los datos de una reserva en el PDF. Rellénalos a mano.» (“I couldn’t find booking details in the PDF. Fill them in by hand.”)

There’s no text recognition in images (OCR). A photo of the ticket, a screenshot or a scanned PDF is stored and opens offline, but isn’t read. Nor is a password-protected PDF.

Where the app reads a PDF

WhereWhat happens
Trip documents → «Añadir documento» (“Add document”)When you choose the file, the first PDF is read. The type and title are suggested automatically, unless you’ve already touched them. When you tap «Guardar» (“Save”), the booking reference, dates, holder and tags are applied.
A document’s card → «Añadir» (“Add”)The added PDF is read and whatever is empty gets filled in. The card says what it filled in and asks «Revisa que esté bien.» (“Check it’s right.”)
Accommodation → «Desde el PDF de la reserva» (“From the booking PDF”)It creates the document, reads it and, if it’s accommodation with dates, adds its nights. If it’s something else, it leaves it in Documents with its type.
WalletNot read: the wallet holds your passport, ID card or annual insurance, not bookings.

In Documents, while reading, the app says «Leyendo el PDF en este dispositivo…» (“Reading the PDF on this device…”) (in Accommodation, «Leyendo el PDF…»). What it understood appears in a line starting with «Leído en este dispositivo:» (“Read on this device:”). More about documents in Offline travel documents.

The 8 booking classes

Each class sets the document type, the tag that gets added and which labels are searched for the dates. To recognise it, typical words count, each one only once even if it repeats:

ClassDocument typeTagWords that count (examples)
AccommodationBooking«Alojamiento» (“Accommodation”)check-in, check-out, «3 noches» (nights, nuits, notti, noites, nits, Nächte), habitación, huésped, hotel, hostal, apartamento, anfitrión (8 groups)
FlightTicket«Vuelo» (“Flight”)boarding or embarque, gate, asiento or seat, vuelo or flight, aeropuerto, equipaje, «Terminal 2» (7 groups)
TrainTicket«Tren» (“Train”)tren, train or Zug; estación, stazione or Bahnhof; «coche 5», vagón, carriage; andén, platform, quai, binario, Gleis (4 groups)
BusTicket«Autobús» (“Bus”)autobús, bus, autocarro; estación de autobuses; dársena (3 groups)
BoatTicket«Barco» (“Boat”)ferry, barco, naviera; camarote or cabin; «puerto de»; vehículo embarcado (4 groups)
ActivityEntry ticket«Actividad» (“Activity”)entradas or tickets; tour, visita guiada, excursión; voucher, bono, código QR; punto de encuentro (4 groups)
CarCar and driving«Coche de alquiler» (“Rental car”)recogida or pick-up; devolución or drop-off; vehículo; alquiler or rental; conductor or driver; fianza, franquicia or deposit (6 groups)
InsuranceInsurance«Seguro de viaje» (“Travel insurance”)póliza or policy; asegurado or insured; cobertura or coverage; seguro de viaje or travel insurance (4 groups)

The 65 brands it recognises

A recognised brand adds its tag to the document («Booking.com», «Renfe») and weighs heavily when deciding the class. If yours isn’t listed, the booking can still be read by its words and labels: only the provider tag is missing.

ClassBrandsHow many
AccommodationBooking.com, Airbnb, Expedia, Hotels.com, Vrbo, Agoda, Trip.com, Hostelworld, Marriott, Hilton, Accor, Meliá, NH Hotels, Paradores14
FlightRyanair, Vueling, Iberia, Air Europa, easyJet, TAP Air Portugal, Volotea, Binter, Lufthansa, Air France, KLM, British Airways, Wizz Air, Transavia, ITA Airways15
TrainRenfe, Iryo, Ouigo, SNCF, Trenitalia, Italo, Deutsche Bahn, Eurostar, Comboios de Portugal9
BusFlixBus, ALSA, BlaBlaCar3
BoatBaleària, Trasmed, Naviera Armas3
ActivityGetYourGuide, Tiqets, Civitatis, Viator, Klook, Musement, Ticketmaster7
CarHertz, Avis, Europcar, Sixt, Enterprise, Goldcar, Rentalcars.com, Discover Cars, Cicar9
InsuranceIATI Seguros, Heymondo, InterMundial, Mondial Assistance, Allianz Travel5

Some brands only count in their full form, because their bare name is an everyday word: “Booking.com” or “Booking B.V.” (a booking is just a reservation), “Italo Treno”, “Enterprise Rent-A-Car”, “Avis Budget” or “alsa.es”. The bare name (“booking”, “alsa”, “avis”) is a weak mention.

How it decides what it is and who it’s from

The class and the provider come from a points tally, the same for every PDF:

What adds upPoints
Each time a brand’s full name appears (up to 3 count)5
Each weak mention on top of the full name (up to 3)1
The brand in the file name (“Airbnb_reserva.pdf”)5
Each distinct group of words typical of the class2
  • A class’s score is its words plus its best brand.
  • The class with the most points wins, and only if it has at least 4: two typical words are enough (a hotel with no platform is recognised as accommodation), a lone “hotel” isn’t.
  • The provider is named if its brand, in that class, has at least 5 points: its full name has to appear, or be in the file name. Three weak mentions add up to 3 and aren’t enough.

Which details it extracts

DetailHow it finds itWhere it ends up
Booking referenceWhat follows a booking reference label: 4 to 25 letters, digits, dots or hyphens, with no lowercase and at least one digit, or 5 to 8 capitals (a PNR).«Referencia o localizador» (“Reference or booking code”)
HolderA line starting with a holder label. Only letters, spaces, dots, hyphens and apostrophes, 2 to 60 characters.«A nombre de» (“In the name of”)
Start date and timeThe first date within 90 characters after the class’s check-in, pick-up, outbound or start label.«Desde» (“From”), and on the stay, the check-in time
End date and timeThe same, with the check-out, drop-off, return or end label. It has to be after the start.«Hasta» (“To”), and on the stay, the check-out time
Price and currencyThe amount within 45 characters after “Precio total” and its variants; failing that, after “Total”; and failing that, after “Precio”.The accommodation stay
Free cancellationThe first date within 110 characters after “Cancelación gratuita” or its variants.The stay, with its reminders
Non-refundableThe phrase anywhere, if there’s no free cancellation.The notes: «No reembolsable.» (“Non-refundable.”)
Property nameAfter “Nombre del alojamiento” and variants; failing that, the line above the address (that’s how Booking.com lays it out); failing that, the first line of several words with no digits among the first 10.The title and the place on the map
AddressAfter “Dirección” and variants; failing that, a line among the first 60 with at least two commas, some digit and no dates, prices or links.The place on the map
PhoneAfter “Teléfono”, “Phone”, “Tel” or “Telefon”.The place on the map
Flight numberTwo airline characters and 3 or 4 digits (“FR 1234”).The title: «Vuelo FR1234»

The title is built according to the class: the hotel’s name (or «Alojamiento de Booking.com», “Booking.com accommodation”, if it doesn’t appear), «Vuelo» with its number, or the class and the provider («Tren · Renfe»).

The labels it recognises, language by language

They’re matched ignoring case and accents. A dash means that language has no form of its own in the list (it often matches another: the Catalan “número de reserva” is the Spanish form).

DetailSpanishEnglishFrenchItalianPortugueseCatalanGerman
Check-in (accommodation)check-in, entrada, llegadacheck-in, arrivalarrivéearrivochegadaentradaAnreise
Check-out (accommodation)check-out, salidacheck-out, departuredépartpartenzasaídasortidaAbreise
Outbound (tickets)salida, ida, fecha, fecha de viaje, de vuelo o de salidadeparture, outbound, datedépartpartenza, datadatadata
Return (tickets)vuelta, regresoreturnretourritornotornada
Pick-up (car)recogidapick-upprise en chargeritiroretiradaAbholung
Drop-off (car)devolución, entregadrop-off, returnrestitutionriconsegnaentregaRückgabe
Start and end (insurance)desde, inicio, fecha de efecto / hasta, fin, vencimientofrom, start date, effective / to, end date, valid until, expiry
Day (activity)fecha, día, válido paradate, day, valid on, valid fordatadatadata
Booking referencelocalizador, referencia, número o código de reserva, número de confirmación, número de pedidobooking number, booking reference, confirmation number, confirmation code, reservation number, order number, PNR, record locatornuméro de réservation, code de réservationcodice prenotazionenúmero da reserva, código da reservaReservierungsnummer, Buchungsnummer
Total priceprecio total, importe total, total a pagar, total pagadototal price, total amount, amount paid, grand totalmontant total, prix totalprezzo totalepreço totalpreu totalGesamtpreis, Gesamtbetrag
Free cancellationcancelación gratuita, cancelar gratis, cancelar sin coste, sin cargo o sin gastosfree cancellation, cancel for free, cancel free of charge, cancel without chargeannulation gratuite, annuler gratuitementcancellazione gratuitacancelamento gratuitocancel·lació gratuïtakostenlose Stornierung, kostenlos stornieren
Non-refundableno reembolsablenon-refundablenon remboursablenon rimborsabilenão reembolsávelno reemborsablenicht erstattungsfähig
Addressdirección, dirección del alojamiento, ubicaciónaddress, property addressadresseindirizzomorada, endereçoadreçaAnschrift
Property namenombre del alojamiento, alojamiento, establecimiento, anuncio, hotelproperty name, hotel name, property, accommodation, listinghébergement, établissementstrutturaalojamentoallotjamentUnterkunft
Holdernombre del cliente, del huésped o del titular, huésped principal, reservado por, pasajero, conductor principal, aseguradoguest name, lead guest, booked by, passenger, main driver, insurednom du clientnome do hóspedenom del client

As a last resort, the price is also searched for after the bare word in any of the seven languages: precio, price, importe, amount, montant, prix, prezzo, preço, preu.

Dates and times

FormatExamples it readsRule
ISO 86012026-10-09Year, month and day.
Numeric09/10/2026, 9.10.26, 09-10-2026Day then month, as almost everywhere in the world. Month then day only if it can’t be anything else: 10/25/2026 is October 25.
In words9 de octubre de 2026, October 9, 2026, 9. Oktober 2026, 9 d'octubre de 2026, vie, 9 octMonths and their abbreviations in the seven languages, with ordinals (“3rd”, “1er”, “1º”).
No yearvie, 9 octIt picks the year (the previous, the same or the next) that puts the date closest to the start of the trip, or to today if the trip has no dates yet.
  • Abbreviations that are also words (out, des, set, gen, mag, lug, ott, mai, mar) only count as a month if a year follows: “3 out of 5 guests” isn’t October 3 (“out” is October in Portuguese).
  • In a table with “Check-in Check-out” on one line and both dates below, the first date after “Check-out” is the check-in date, and it’s skipped.
  • If there’s no label, it uses the first date that doesn’t follow “fecha de reserva”, “emitido”, “booked on”, “fecha de nacimiento” or “caduca” (booking date, issued, date of birth, expires). For insurance, it doesn’t guess.
  • Accommodation with “3 noches” (3 nights) and no readable check-out date: check-out is worked out by adding the nights to check-in.
  • An end date more than 62 days after the start is dropped: it’s some other date that slipped in.
  • Times: 15:00, 15h00, 3:00 PM or 3 PM. For the start time, the one with “desde”, “from” or “a partir de” wins; for an accommodation’s check-out, the last one with “hasta”, “until” or “before”: “de 07:00 a 11:00” (from 07:00 to 11:00) means check-out until 11:00.

Price and currency

The currency comes from the symbol or code next to the amount, before or after it (“€ 390,00”, “390,00 EUR”), or from the code in brackets after “Total (EUR)”. It recognises 37 ISO 4217 codes:

EUR USD GBP JPY CHF CAD AUD MXN ARS COP CLP PEN BRL DKK SEK NOK PLN CZK HUF
RON BGN TRY MAD THB CNY HKD SGD NZD ZAR INR KRW ISK IDR VND EGP AED ILS
SymbolRead as
EUR
£GBP
$ and US$USD
¥JPY
R$BRL
C$CAD
A$AUD

Separators are read as each country writes them: 1.234,56 and 1,234.56 are the same, and so is 1 234,56; “1.234” is one thousand two hundred and thirty-four, and “12,50” is twelve point five.

A bare “$” is always read as US dollars and a “¥” as yen. If you book in Mexican pesos or Chinese yuan and the PDF only shows the symbol, correct the currency on the stay. If there’s no currency, the stay takes the trip’s.

What it does with what it reads

There’s one rule: it never overwrites what someone has typed.

  • On a new document, if you change the type or title while it’s reading, yours stays. If you change the type that was read (a «Reserva», “Booking”, that you turn into «Entrada», “Entry ticket”), the tags from the reading aren’t added.
  • On an existing document, only the booking reference, holder and dates are filled in if they’re empty, and the type only if it was «Otro» (“Other”). If the type read is different, the card offers «Cambiar el tipo a…» (“Change the type to…”) without changing it.
  • Two tags are added, the provider’s and the class’s («Booking.com» and «Alojamiento»), without removing the ones it had.

If it’s accommodation with check-in and check-out, and the document is a booking, it’s tied to a stay, that hotel’s nights on the trip:

  1. If there’s already a stay linked to that document, it’s completed (times, price, cancellation) without touching what it has.
  2. If not, it looks for the hotel: the document’s related place, or an accommodation on the map with the same name (at least 60% of the words in common, not counting “hotel”, “apartamento”, “de” or “the”).
  3. If that hotel has an option with no linked document that matches those nights, it becomes booked, with the document linked and the dates from the PDF.
  4. If the hotel isn’t on the map, its address goes to Nominatim (OpenStreetMap’s search engine), or its name within the destination area. If you already have accommodation less than 150 m from the result, it’s that one; if not, the place is created with its address and phone, and its photos are looked up.
  5. If there was no option, a new booked stay is created, at that place if it was found. Offline, or if Nominatim finds nothing, it stays unplaced, with its name, and you place it by hand later.

The stay brings the accommodation reminders: free cancellation, «Mañana duermes en…» (“Tomorrow you sleep at…”) and «Hoy dejas…» (“Today you leave…”) (full table in Documents). If a booking document has dates but wasn’t tied to a stay, its card offers «Es un alojamiento: añadir estas noches» (“It’s accommodation: add these nights”).

Nominatim only receives the address text (or the hotel name and the area), with at least 1.1 seconds between requests, as its usage policy asks. Never the booking reference, the holder or the price.

Example: a Booking.com confirmation for Lisbon

Limitations

  • No photos or scans. Only text is read; there’s no OCR.
  • Tested with sample texts, not with real confirmations from each provider. The tests mimic what pdf.js extracts from Booking.com (in Spanish and English, with a table), Airbnb (in both languages), a hotel with no platform, Ryanair, Renfe and Europcar, and a generated PDF is read from start to finish. It hasn’t been tested with each of the 65 brands.
  • A PDF with jumbled text (columns that pdf.js returns in a different order) can leave labels far from their values, and the detail doesn’t come out.
  • Only one ticket per document. A return-trip PDF gives the outbound and return dates, but not two documents, nor stopovers.
  • Only the first PDF when you choose several files at once while creating a document.
  • Everything read can be corrected. Always look at the card: the app asks you to with «Revisa que esté bien.»

If your booking wasn’t read properly

Correct the details by hand on the card: they save themselves and the reading won’t overwrite them again. And if you’d like the next version to read it better, tell us in the contact form with the reason “A PDF booking that wasn’t read properly”. It helps to say:

  • The provider and the language of the confirmation.
  • Which detail failed (the check-out date, the price, the hotel name) and what the PDF said next to it, with the label exactly as written.
  • Whether the PDF is a printed email, a download from the provider’s website or a boarding pass.

Don’t paste real booking references, names, addresses or card numbers: swap them for made-up ones before sending (“XXXX1234”, “Ana Ejemplo”). The form doesn’t accept attachments, and the PDF isn’t needed: the lines that fail are enough.

Check it yourself

You don’t have to take any of this on trust: these are the steps to see it in the app with your own eyes.

  1. Open a trip with dates and go to «Alojamiento» (“Accommodation”).
  2. Tap «Desde el PDF de la reserva» (“From the booking PDF”) and choose a hotel’s PDF confirmation. While it reads you see «Leyendo el PDF…» (“Reading the PDF…”).
  3. If it’s accommodation, «Leído en este dispositivo:» (“Read on this device:”) appears with the name and the nights, and the stay shows up in the nights strip.
  4. Go to «Documentos» (“Documents”) and open the document that was created: the booking reference, dates and the provider and class tags are already there.
  5. Try «Añadir documento» (“Add document”) in «Documentos» with a train or plane ticket: the type changes to «Billete» (“Ticket”) and the title is suggested automatically.

Open the app

Frequently asked questions

Is the PDF uploaded to a server to read it?

No. It’s read on your device with pdf.js, without AI and offline. The only thing that can leave is the address of a hotel that isn’t on your map, to OpenStreetMap’s Nominatim, to place it; the file, the booking reference and the holder don’t.

My provider isn’t among the 65 brands. Is it still read?

It may be. The class is also recognised by its words (two groups are enough, like “check-in” and “habitación”), and the details are found by their labels, not by the provider. What’s missing is the tag with the brand’s name.

Does it read plane and train tickets, or only hotels?

All 8 classes: accommodation, flight, train, bus, boat, activity, car and insurance. Only accommodation creates nights on the trip; a ticket stays as a document with its date, time, booking reference and, if it has a flight number, the title «Vuelo FR1234» (“Flight FR1234”).

Why did it set the wrong year?

If the confirmation doesn’t write the year (“vie, 9 oct”), it picks the one that puts the date closest to the start of the trip, or to today if the trip has no dates. Set the trip’s dates before adding bookings, or correct the date on the card.

Can it read a password-protected PDF?

No. It’s still stored and opens in the viewer if your device allows it, but you fill in the details by hand.

Sources and references

The original documentation for what is cited here, checked on this page’s review date.

  1. PDF.js Mozilla
  2. PDF.js repository (code and Apache-2.0 licence) Mozilla, on GitHub
  3. ISO 4217, currency codes (maintenance agency) SIX Group
  4. Nominatim Usage Policy OpenStreetMap Foundation
  5. Nominatim: Search API Nominatim

Keep reading

This page in Markdown, to read it with other programs