Blog

Hoe Cal.com een iOS/Android-app uitbracht met Expo en Chrome/Firefox met WXT in één codebase

Leer hoe Peer en het team een native app in minder dan 3 weken uitbrachten.

Peer RichelsenDec 17, 2025

Eén codebase. Vijf platforms. Twee app stores. Vier browsers.

Uitgebracht in minder dan drie weken.

Cal.com draait altijd al om mensen ontmoeten waar ze al zijn.

Voor plannen betekent dat overal: op je telefoon, in je browser, in het tabblad dat je nooit sluit, op de laptop die je voor werk gebruikt en op het apparaat dat je pakt als je de deur uit rent.

Veel van jullie hebben erom gevraagd en uiteindelijk besloten we het te proberen. Deze week kondigden we aan:

  • Een native iOS-app

  • Een native Android-app

  • Een Chrome-extensie

  • Een Firefox-extensie

  • Een Safari-extensie

  • Een Edge-extensie

En we deden dit niet verspreid over maanden of kwartalen.

We brachten dit allemaal in minder dan drie weken van idee naar productie uit.

Zonder het product op te splitsen in een dozijn repositories die in de loop van de tijd langzaam uit elkaar drijven.

We deden het met één codebase.

Het kernidee: Cal.com overal uitbrengen zonder Cal.com vijf keer uit te brengen

Historisch gezien leven “mobiele app” en “browserextensie” in verschillende universums.

  • Mobiel wil React Native, native build tooling, app store-workflows, pushmeldingen, deep linking, enz.

  • Extensies willen content scripts, background/service workers, permissies, storage-API's, browser-eigenheden en het eindeloze spel van “werkt in Chrome maar…”.

De gebruikelijke aanpak is om de splitsing te accepteren:

  • aparte teams

  • aparte stacks

  • aparte releaseprocessen

  • aparte bugs

  • aparte inconsistenties in de UI

Dat voelde niet als de Cal.com-manier.

We wilden dat Cal overal hetzelfde product aanvoelde. Dezelfde UI. Hetzelfde mentale model. Dezelfde functies. Dezelfde snelheid van iteratie.

Dus bouwden we het zo.

iOS + Android: mogelijk gemaakt door de nieuwste Expo en React Native

Onze iOS- en Android-apps worden aangedreven door de nieuwste Expo (expo.dev) en React Native (RN).

Expo is zover gekomen dat je het beste van twee werelden krijgt:

  • uitstekende developer experience

  • serieuze productiegeschiktheid

  • flexibiliteit wanneer je native moet gaan

Het belangrijkste is dat Expo past bij een bredere visie waar we sterk om geven:

Web en native zouden niet aanvoelen als aparte producten.

Ze zouden moeten voelen als verschillende oppervlakken van hetzelfde systeem.

Extensies: mogelijk gemaakt door WXT

Voor browserextensies bouwden we op wxt.dev.

Extensies zijn nog steeds een van die gebieden waar tooling vreemd genoeg in het verleden kan blijven hangen. WXT laat het modern aanvoelen:

  • heldere structuur

  • verstandige defaults

  • betrouwbare builds voor meerdere browsers

En ja, we bouwden voor Chrome, Firefox, Safari en Edge.

Safari alleen is meestal al genoeg om teams af te schrikken van ondersteuning voor meerdere browsers. Maar het doel was nooit “nu Chrome, later de rest”.

Het doel was Cal overal.

Het leuke deel: Chrome-extensie-UI aangedreven door Expo Web

Hier komt het deel dat nog steeds een beetje surrealistisch voelt:

Onze Chrome-extensie-UI wordt aangedreven door Expo Web.

Dat betekent dat de UI van de extensie geen aparte frontend is met een eigen componentsysteem en stijlverschuivingen. Het is opgebouwd met dezelfde UI-aanpak die we al voor mobiel gebruiken, draaiend op het web binnen de extensieomgeving.

Dus als ik één codebase zeg, bedoel ik dat op een manier die echt telt:

  • gedeelde schermen

  • gedeelde componenten

  • gedeelde design-primitives

  • gedeelde logica

  • gedeelde snelheid

De WXT-app zelf draait binnen /extension/entrypoints/content.ts, waarna de expo-web-app als iframe wordt geladen. Dit is de meest gebruikelijke manier om "sidebar"-Chrome-extensies te bouwen en deze truc leerde ik van Wilson Wilson (@euboid). Helaas heeft de officiële Chrome-extensie "popup" een max-height van 600px.

We hebben zelfs wat browser-only API's gebruikt, zoals het injecteren van onze Cal.com-widget in mail.google.com en calendar.google.com, wat eenvoudig kan worden gedaan in de /extensions-map van WXT.

Uit mijn ervaring is deze combinatie: native iOS + Android via Expo, extensies voor meerdere browsers via WXT, extensie-UI via Expo Web, alles samengebracht in één coherente codebase iets dat ik persoonlijk nog niet eerder zo heb gezien.

Misschien bestaat het ergens. Het internet is groot.

Maar ik heb het niet gezien, en er was zeker geen playbook dat we konden volgen.

Dus maakten we er zelf een.

Minder dan 3 weken… omdat de basis goed was

Zo snel uitbrengen ging niet om heldendom of crunch.

Het ging om de juiste basis.

Alles leunt op de nieuwste en beste Cal.com API v2, die OAuth gebruikt voor autorisatie. Dat betekende:

  • nette auth-flows

  • veilige toegang

  • een consistent model over apps en extensies heen

  • geen hacks, geen shortcuts

Dezelfde API drijft mobiel, web en extensies aan. Geen “alleen-extensie-endpoints”. Geen “mobiele uitzonderingen”.

Gewoon één API, ontworpen om met het ecosysteem mee te schalen.

👉 Als je apps of integraties bovenop Cal.com bouwt, is dit je startpunt:
https://cal.klipni.com/help/apps-and-integrations/oauth

Die OAuth-basis maakt het realistisch om nieuwe planning-apps zo snel uit te brengen zonder concessies te doen aan veiligheid of het mentale welzijn van ontwikkelaars.

Waarom dit ertoe doet (naast “kijk wat we hebben gebouwd”)

Verzenden naar veel platforms is alleen indrukwekkend als het onderhoudbaar blijft.

De echte winst is niet de checklist met platforms. De echte winst is:

  • Consistentie: functies landen overal, niet “mobile first, extension later”

  • Snelheid: één plek om te bouwen, één plek om te fixen

  • Kwaliteit: minder platformspecifieke verschillen

  • Momentum: het team bouwt aan product in plaats van aan glue code

Extensions laten ons rechtstreeks in workflows leven. Mobile laat ons in de echte wereld leven. Samen wordt dat oppervlak een productvoordeel.

Credits waar die horen

Dit is niet gebeurd door één persoon. Maar twee mensen waren enorme multiplicatoren:

  • Wilson Wilson (@euboid), een enorme hoeveelheid van de ondersteuning voor de browser extension, cross-browser edge cases en “dit is de truc die echt werkt”-kennis kwam van Wilson.

  • Beto (@betomoedano), enorm veel van de Expo-expertise en praktische hulp die “dit zou moeten werken” omzet in “ziet er goed uit, voelt goed” kwam van Beto.

  • en het hardwerkende team bij call, namelijk: ikzelf, Dhairyashil Shinde, Carina Wollendorfer en

    Volnei Munhoz en Claude Code.

Bedankt allemaal. Echt.

Wat is de volgende stap

Leuk weetje: onze apps zijn nog niet live gegaan, wat stiekem hilarisch is. Het aanmeldproces voor de App Store duurt langer dan de volledige ontwikkeling van de app zelf. Om de een of andere reden zijn er nog steeds KYC-problemen met ons bedrijf (we hebben een paar jaar geleden een nieuwe naam aangenomen, mismatch van het D-U-N-S-nummer, niet-Amerikaanse medewerker die een Amerikaans bedrijf aanstuurt, bla bla bla.)

Screenshot van een e-mail van Apple developer support

Soms wou ik dat mobiele app-ontwikkeling hetzelfde tempo kon ervaren als waar we op het web aan gewend zijn, maar dat is erg onwaarschijnlijk.

Hoe dan ook, pllleeease meld je aan voor onze wachtlijst op cal.com/app en krijg een melding zodra de productie-apps live gaan in de stores. Volgens het enrolmentteam zijn het nog maar een paar dagen, maar de feestdagen komen eraan dus je weet het nooit.

De codebase is nog steeds behoorlijk rommelig met grote componenten, maar we ruimen die nu op.

Uiteindelijk is het spannendste dat we naar “Cal.com overal” kunnen gaan met zo weinig engineering-overhead om te onderhouden.

Nu hebben we een basis waarop de volgende stap shippen voelt zoals het hoort:

  • bouw het één keer

  • ship het overal

  • itereren snel

Dat is de norm.

En dat is een behoorlijk leuke norm om te halen.

Peer Richelsen

Post by

Peer Richelsen

Co-Founder