Skip to content

Build a custom shop template

Custom templates are website files in a ZIP, not variations of Yard or Flame. You choose the layout, write the HTML and CSS, and add JavaScript interactions. Bottle supplies the shop’s public products and links. Purchases, accounts and payments remain on Bottle’s own pages.

This is a WordPress-style upload workflow, not WordPress theme compatibility. PHP, plugins, server code, build hooks and npm installs are not supported. Upload the finished browser files, not a development project.

If this is your first template, follow the step-by-step walkthrough. Its small working ZIP is generated from the exact code shown in the guide.

Use these guides as you build:

  • Reference: manifest options, public data, supported values and the browser interface.
  • Recipes: navigation, search, categories, sorting and content pages.
  • Design and language: responsive layouts, accessibility, product wording and clear actions.
  • Troubleshooting: packaging, upload errors, preview and browser restrictions.

There is no separate Bottle templating language, Liquid syntax or server-side tag system. You use normal HTML, CSS and JavaScript, plus Bottle.ready(callback) and Bottle.navigate(path). The JSON manifest tells Bottle which finished files to load.

Download Harbour, a complete HTML/CSS/JavaScript example. It includes its own responsive header, homepage, searchable catalogue, category links and content-page layout. You can edit it yourself or give it to a designer, Claude or ChatGPT.

The ZIP contains:

bottle.template.json
index.html
style.css
shop.js

Put the manifest at the root of the ZIP, not inside another folder. Images can live in a folder such as images/.

ZIP only the template files and their image folders. Remove operating-system extras such as .DS_Store and __MACOSX, and do not include source maps, dependency folders or build tools.

{
"format": "bottle-template",
"schemaVersion": 1,
"name": "My custom shop",
"description": "A responsive shopfront designed for our business.",
"pages": {
"home": "index.html",
"products": "catalogue.html",
"category": "catalogue.html",
"page": "page.html"
},
"styles": ["style.css"],
"scripts": ["shop.js"]
}

There is no template: yard or template: flame field. This is your own template.

The homepage is required and must be index.html. Other layouts are optional; pages you do not supply keep Bottle’s standard design. You can reuse one HTML file for several layouts and use data.page.type to decide what to show.

Layout Used for
home The homepage, /
products The product catalogue, /products
category Category pages, /c/CATEGORY
page The shop’s published custom content pages

Product detail pages, basket, checkout, account pages and other built-in pages keep Bottle’s supported layout. The template controls its own header and footer on the pages it supplies.

You can list up to four stylesheets and four JavaScript files. Bottle loads them in the listed order. Use browser-ready JavaScript; modules with external imports are not supported. The manifest name is up to 80 characters and its description up to 240.

Use ordinary, semantic HTML for the page body. A complete HTML document with a title is fine. Bottle installs the stylesheets and scripts named in the manifest: do not add <script>, <style> or <link> tags yourself.

Use classes and stylesheets rather than inline style or onclick attributes. Add event listeners from your JavaScript file. Search inputs and buttons are supported; login, address, payment and other data-entry forms belong on Bottle’s protected pages.

Reference bundled pictures with relative paths:

<img src="images/hero.webp" alt="Our local delivery team" />
.hero {
background-image: url('images/hero.webp');
}

Paths are relative to the file that contains the reference. Keep the stylesheet at the ZIP root if it needs pictures in images/. Parent-directory references such as ../images/hero.webp are not supported.

Pictures must be JPEG, PNG or WebP. Bottle checks the actual image format, removes metadata and re-encodes them before use. SVG files, remote images, remote fonts, CSS @import and CDN libraries are not accepted. Public product pictures supplied by Bottle can also be displayed.

Use lowercase filenames with letters, numbers, hyphens or underscores. Filenames cannot contain spaces, absolute paths, .. or URLs. Up to three nested folders are supported.

Bottle’s small browser interface connects the template to the public shop. It does not expose an API key or a customer’s account.

Bottle.ready(function (data) {
document.querySelector('h1').textContent = data.shop.name;
// Render your product cards using data.products.
});
document.querySelector('#shop-all').addEventListener('click', function () {
Bottle.navigate('/products');
});

The callback receives:

Field Contents
shop Public business name, phone, email and currency (GBP)
products Public products for this view: ID, name, description, path, price in pence, availability, kind and pictures
categories Public category names, slugs and shop paths
navigation Public shop menu labels and paths
page Page type, path, title, category slug and, on a content page, sanitised published text-section HTML
links Homepage, catalogue, basket and account paths

Product pictures are provided in product.images, with src, alt, width and height. Link to product.path using Bottle.navigate(product.path) to open the protected product page. That page handles cylinder swaps, charges, quantities and adding to the basket.

The interface is bounded to 500 products, 100 categories and four pictures per product. catalogueTruncated tells you when more products exist. Category views are filtered before the data is supplied. Products also include their public categorySlugs. Do not make a large catalogue look complete when catalogueTruncated is true; tell shoppers to narrow it down by category.

Bottle.navigate(path) accepts known Bottle shop paths only. It does not accept external URLs, arbitrary API routes or query strings. For links in your template, prevent the browser’s default navigation and call this function instead. The Harbour example includes that handler.

Treat public strings as text: use textContent, not innerHTML, when rendering names, prices and descriptions. page.html is the exception: Bottle supplies already-sanitised published shop content. Do not expect private trade prices, customer records, cylinder balances, basket contents, preview tokens or account details.

page.html contains the text from published text and text-with-picture sections, up to 32 KB. It does not recreate the section editor’s picture, gallery, product or other widget layouts. Keep those on Bottle’s standard pages by omitting the page layout, or provide their presentation in your template. The original sections stay saved when you switch templates.

  1. ZIP the files, with bottle.template.json at the root.
  2. Open Shop → Design → Look → Browse templates → Upload.
  3. Drop the ZIP into the upload area. Bottle checks it and shows the included files and supported layouts.
  4. Choose Use in draft. This does not publish your shop.
  5. Check the shop preview on desktop and phone widths. Test product links and make sure protected product, basket and account pages remain reachable.
  6. Publish when you are happy.

Saved templates can be reapplied to the draft. To return to a Bottle design, select one from the library. To abandon unpublished changes, use Discard changes. Existing products, prices, customers, orders and page content are not replaced by a code template.

Templates used by the draft, live shop or your assistant’s saved undo cannot be removed. Switch the draft and live shop to another template first. If an assistant undo still needs it, undo or replace that assistant change too.

  • ZIP: 4 MB compressed and 8 MB of uncompressed files.
  • Up to 32 files, including the manifest, and up to eight pictures.
  • Each picture: up to 1 MB and 4 million pixels.
  • Supported files: the manifest, HTML, CSS, JavaScript, JPEG, PNG and WebP.
  • Each HTML, CSS or JavaScript file: 256 KB. The manifest: 16 KB.
  • Combined JavaScript: 256 KB. Combined CSS: 2 MB.
  • Processed template: up to 4 MB per layout, within 12 MB across layouts.
  • A business can retain 20 templates, within 40 MB of source packages and processed code bundles.

The file check and import both use the business’s rolling 50 MB upload-processing allowance over 24 hours. Repeated checks therefore count too. Processing is limited and timed; a rejected upload does not replace the live shop. Corrupt, encrypted and unsupported archives are rejected.

Uploaded code runs in a browser frame with an opaque origin. Bottle applies an HTTP sandbox policy as well as the frame’s sandbox. Templates cannot read Bottle cookies, access the parent page, use browser storage, submit forms, open popups or make direct API requests. Styles and scripts are bundled; the resource policy permits public catalogue pictures, not external scripts, images or API calls.

Browser restrictions do not prevent every possible external request: JavaScript can attempt to navigate its own frame. Bottle removes the frame and returns to its supported layout when it navigates unexpectedly, but the initial navigation request can still happen. No private customer information is supplied to the template.

The API never executes uploaded JavaScript, runs a template build, or installs its dependencies. Source files and processed templates are stored in the business’s private asset storage and resolved through the current shop’s approved revision.

This is not a promise that any uploaded JavaScript is safe or well written. A template can still display misleading content or run slow code in the visitor’s browser. Bottle blocks initial credential/payment forms, but JavaScript can change its own interface. Only upload templates from someone you trust, inspect their code and test the result. Never ask a template to collect passwords or payment details. An AI review is useful feedback, not the security boundary.

Create a Bottle shop template ZIP using the format in this guide. Include bottle.template.json, index.html, style.css and shop.js. Use independent, responsive HTML and CSS—not Yard or Flame. Use Bottle.ready for public products and Bottle.navigate for shop links. Put styles and scripts in manifest-listed files, not HTML tags. Do not use remote resources, server code, credentials, login forms or payment forms. Keep the design accessible, support reduced motion and make the phone layout as good as desktop. Start from the Harbour example and return the finished browser files.

For a fuller brief, including product states and writing style, use the AI authoring brief. Give your assistant the reference as well as the brief; do not ask it to guess fields or features.

If you only want to change colours, fonts and built-in sections, use the simpler colour-theme pack format instead.