Skip to content

Web app (UI)

The fetch(bible) web app is a generic bible reading app that can be embedded within your own project, and it can also be customised, and interacted with via Javascript postMessage calls.

Also see the web enhancer



  • Works offline
  • Swipe to change chapter
  • Scroll through entire books
  • Show multiple translations (both landscape and portrait)
  • Private (no tracking of individuals)

Coming soon:

  • Customise font and size
  • Search
  • Audio


You can use the app in the following ways:

  1. Embed it as an iframe
    • <iframe src=''>
  2. Load it in a webview in a native app
  3. Navigate to the app and provide a back URL
    • e.g.
    • Doesn’t support interaction via postMessage
  4. Self-host on your own subdomain
    • npm install
  5. Extend the app with your own components/routes


You can pass config to the app when it first loads via search params embedded within the # of the URL. They should be in the same format as regular search params (i.e. you can use URLSearchParams to create them).



If you embed the app as an iframe or webview then you can use Javascript postMessage calls to change the app’s config at runtime and also get status updates about what passage the user is reading and some actions they take.


These are the params available for use in the URL # and/or postMessage calls:

darktrue|false[auto]Whether to force dark/light theme. Only use this if your app already has a theme setting that you want to sync with, and also update it by listening for changes via this app’s own theme setting).
statusstring[disabled]A status message to display in the toolbar (must be short and may get cut off).
hue0 - 360290Color hue for app’s theme.
saturation20 - 8070Color saturation for app’s theme (limited to 20-80% for readability).
backtrue|URLfalseWhether to show a back button in the toolbar (iframes should listen to click via postMessage, don’t use URL if using an iframe/webview).
button1_iconcoordinates[disabled]The icon to display for a custom button in the toolbar. It must be a string for an SVG <path d=""> that must conform to a 48x48 viewport (any value from a Material icon/symbol will work).
button1_colorCSS colorcurrentColorA color for the button’s fill.
translll_ttt[auto]A translation to force use of (comma-separate for multiple). Must be a fetch(bible) id (preview any translation to find the id in the url).
searchstring[auto]A passage reference in the language of the given translations (English names and book codes always work, e.g. Genesis 1:1).


From the app

Every message sent from the app via postMessage contains the following data. The event type is the most important but every event also reports what the user is currently reading.

typeready|translation|verse|back|button1|darkThe event type
languages[string, ...]The three char language codes (ISO 639‑3) of the translations being viewed
translations[string, ...]The translations currently being used (always at least one)
bookbbbUSX bible book code (in lowercase)
chapternumberChapter number currently being viewed
versenumberVerse number currently being viewed
darktrue|falseWhether the app’s theme is dark (or light)

When the app is ready to receive messages it will emit the ready event. Whenever the user scrolls or changes book the verse event will emit (may be very frequent). Other events trigger for button clicks or other state changes.

To the app

You can use postMessage to send the app a message with {"type": "update", ...} and add any of the config params you’d like to change.

window.addEventListener('message', event => {

    // Only handle events from fetch(bible) app
    const app_origin = ''
    if (event.origin !== app_origin){

    // Once app is ready, update the status text
    if ( === 'ready'){
        // Send an update command to the app
        event.source.postMessage({type: 'update', status: "Custom text"}, app_origin)

    // If user clicks back button in app, hide the app
    if ( === 'back'){

Offline support

The app will work offline by default on most devices, however there are some situations that it won’t. If a user has disabled third-party cookies in their browser it can prevent iframes from caching responses (even though the app doesn’t use any actual cookies).

If this is a problem you should use a method other than iframes to include the app in your own project.