---
title: "Serve an HTML5 creative from a ZIP bundle"
description: "Serve a self-contained HTML5 creative in Epom by uploading its ZIP into the file property of an HTML5 template your network prepares — there is no top-level \"upload zip\" banner type."
type: "howto"
audience: [network-manager]
keywords: [HTML5, zip, html5 zip creative, rich media, template property, bundle, index.html, ad unit]
ui_path: "Account → Advertisers → campaign → banner (Template)"
---

Fetch the complete documentation index at: https://epom.com/ad-server/docs/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Serve an HTML5 creative from a ZIP bundle

You have an HTML5 creative exported as a ZIP — an `index.html` plus its images, CSS, JS and
assets — and you want to serve it as a rich creative. The non-obvious part in Epom: **there is
no "HTML5 zip" banner type to pick**. An HTML5 ZIP is a **template property**, so the creative
is served through a **Template banner** whose template exposes an *HTML5 Zip Creative* field. The
network manager builds the template once, then uploads each ZIP into a banner. This page walks
both sides of that split.

## Who this is for

- **Network managers and traffickers** who have a finished HTML5 bundle and need to get it live —
  jump to [Upload the ZIP into a banner](#upload-the-zip-into-a-banner).
- **Network managers** who need to prepare the reusable HTML5 template first — start at
  [Prepare the HTML5 template](#prepare-the-html5-template).
- **Advertisers**: the stock Advertiser role cannot create Template banners, so send the ZIP to
  your network manager, or ask them to switch Template banners on for your role.

The HTML5 template behind the ZIP field is authored in the Templates section — see
[Create and manage banner templates](https://epom.com/ad-server/docs/guides/advertising/templates.md).

## Prerequisites

- A campaign you can edit.
- An HTML5 creative packaged as a **`.zip`** with a self-contained entry file (commonly
  `index.html`) that references its assets by **relative** paths.
- At least one **HTML5 template** enabled for the target placement type. If none exists, a
  network manager prepares one first (next section).

## Steps

### Prepare the HTML5 template

*(Network-manager step — skip if a suitable HTML5 template already exists.)*

1. Go to **Account → Templates → Add** and save a template for the placement type you serve HTML5
   into (Template banners work on **Site, Non-standard, Mobile site and Application** placements).
2. In **Template properties**, add a property of type **HTML5 Zip Creative**. Give it a **Key** —
   this is the token you reference in the body — and a **Title** (the label advertisers see).
3. In the template **Body**, reference the property key to point at the served bundle. At serve
   time the key resolves to the **URL of the unpacked bundle's folder, with a trailing slash** —
   so you append the entry file yourself:

   ```html
   <iframe src="$$HTML5$$index.html" width="$$WIDTH$$" height="$$HEIGHT$$"
           frameborder="0" scrolling="no"></iframe>
   ```

   (Here `HTML5` is the property's Key.) You can also reference specific assets inside the bundle
   the same way — `$$HTML5$$assets/banner.png`.
4. Activate the template and **Save**. Only active templates appear in the banner form's Template
   picker.

> **Note:** Epom **unpacks the ZIP server-side on upload** and hosts each extracted file. The
> template body does not embed the markup; it points a frame (or asset URL) at the hosted bundle.
> A daily cleanup job removes uploaded ZIPs that no banner property references any more.

### Upload the ZIP into a banner

*(Trafficker step — a role that can create Template banners.)*

1. In the campaign, **Add new banner** → pick the placement type, then set **Banner type** to
   **Template**.
2. Choose the **HTML5 template** in the **Template** combo. The list is filtered to templates
   enabled for this placement type.
3. The **Template properties** subsection now shows the template's fields, including the **HTML5
   Zip Creative** upload. Drop your **`.zip`** into it. The file must end in `.zip` — anything
   else is rejected on save with "Should be a .zip file" — and must unpack within the
   [archive limits](#archive-limits). The field's **File source** switch offers two other ways in:
   **From link** — an `http://` or `https://` address of a public host, at most 10 MB, downloaded
   once on save and stored exactly like an upload — and **Media library**, which picks a ZIP from
   the [Media Library](https://epom.com/ad-server/docs/guides/advertising/media-library.md). The second needs the *Media Library* permission and the
   network's file storage; when an **Ad unit** is chosen the
   picker lists only ZIPs saved at that size, so pick the Ad unit first.
4. Fill any other template properties (text, colors, click URL — whatever the template defines).
5. Pick the **Ad unit** size where the placement type shows one — this is what `$$WIDTH$$` /
   `$$HEIGHT$$` resolve to in the template body. Match it to your creative's design size.
   ![New Template banner with an HTML5 template, a ZIP picked in the HTML5 Creative Zip package field, the Landing Page and the Ad unit](https://epom.com/docs-images/ad-server/html5-zip-creatives/upload-zip.webp)
6. **Save**, then use **Preview** to render the creative.

After saving, the property row shows the uploaded file name with a download link, a delete
button, and a **View contents** toggle that lists the files inside the bundle — use it to confirm
the ZIP extracted with the structure you expect.

#### Over the API

`POST /rest-api/banner/create.do` (and `…/{bannerId}/update.do`) takes the ZIP in one of three ways,
with `bannerType=TEMPLATE` and `templateId`:

- as a multipart upload under the property's key;
- for clients that cannot send files, as `html5ZipUrl`, the URL of the hosted archive. The server
  downloads it once (public `http`/`https` hosts only, at most 10 MB) and stores it exactly like an
  upload, so the [archive limits](#archive-limits) apply to it too;
- as a Media Library ZIP, by reference: `mediaAssetId` when the template has one HTML5 ZIP
  property, `mediaAsset.<property key>` per property when it has several.

A template with several HTML5 ZIP properties takes `html5ZipUrl[<property key>]` per property; a plain
file property of the same template (an image, a video) takes `fileUrl` / `fileUrl[<property key>]` the
same way. See [Entities CRUD → creating each creative type without a file
upload](https://epom.com/ad-server/docs/api/entities-banners.md#creating-each-creative-type-without-a-file-upload).

#### Archive limits

The bundle is unpacked on the server, so what it unpacks *to* is what is limited: the ZIP is not
held to the network's image file-size cap (200 KB by default), and as sent it is bounded only by
the platform's 1 GB upload ceiling. Sizes are counted on the unpacked files, and the
save is refused, with the reason on the ZIP field, when the archive:

- holds more than **1000** files ("The archive holds more than 1000 files.");
- has a single file that unpacks to more than **20 MB**, or unpacks to more than **50 MB** in all;
- contains a path that would land outside the bundle's own folder — an absolute path, a `..`
  segment, a backslash or a drive letter ("The archive contains a file outside its own folder: …").

The three numbers are server-side settings; ask Epom support or your account manager to change them for your network. A
refused archive stores nothing.

## HTML5 ZIP requirements — checklist before you upload

Epom unpacks the ZIP **exactly as it is** — no folder is added or removed — and serves each file
from storage as a static file. That makes these the rules:

- **`index.html` at the top of the ZIP, not inside a folder.** The template points at
  `$$KEY$$index.html`, the top of the bundle. Zipping the *folder* (`Spring_300x250/index.html`)
  instead of its *contents* puts the page one level down, and the banner shows a blank frame or a
  404. Open **View contents** on the banner: `index.html` must be in the first level. (The Media
  Library's preview looks for an HTML page at any depth, so a preview that works there does not
  prove the banner will.)
- **The entry file is the one the template names.** Most templates say `index.html`; a bundle
  whose page is `banner.html` needs the template to say so.
- **Relative paths for every asset** (`img/bg.jpg`, not `/img/bg.jpg`, not
  `C:\…` or `http://localhost/…`). A path starting with `/` points above the bundle.
- **External libraries load from their own host.** A creative that loads a framework (an
  animation runtime, a font) from a CDN works only while that host answers and is not blocked
  where the visitor is. Epom neither copies nor checks it. Bundling the library into the ZIP
  removes that dependency.
- **Macros inside the ZIP are not expanded.** `$$CLICK_REDIRECT_URL$$`, `$$RANDOM$$` and other
  macros work in the **template body**, not in files from the ZIP — those are served untouched.
  Anything the creative needs per impression (the click URL above all) has to be handed to it by
  the template, for example as a parameter on the `index.html` URL that the creative reads.
- **Archive limits**: at most 1000 files, 20 MB per file, 50 MB unpacked in all (see
  [Archive limits](#archive-limits)). There is no separate cap on the ZIP's own size.
- **Name ends in `.zip`.**

## How the click reaches an HTML5 creative

A Template banner has no **Url** field — the landing page is a template property, and the click
is counted only when it passes through Epom's click redirect (`$$CLICK_REDIRECT_URL$$`, see the
[macros reference](https://epom.com/ad-server/docs/reference/macros.md#click-and-conversion-tracking)). Because the ZIP's files
are not processed, the template must pass that URL into the frame, and the creative's own click
handler must open it. If the creative opens a hard-coded landing page, visitors get there but
Epom records **no clicks**. Every template property is also available URL-encoded as
`$$KEY$$ESC$$` and JavaScript-escaped as `$$KEY$$ESC_JS$$` (with `$$KEY$$` the property's key) —
use the URL-encoded form when a value goes into a URL parameter.

## Can an HTML5 creative call an external API (live prices, weather, a data feed)?

Yes — Epom does not restrict it. The ad server adds no Content-Security-Policy to ad markup and
keeps no list of allowed hosts, and every **Ad wrapper** keeps scripts and same-origin requests
allowed (the sandboxed variants included). What decides whether the call works is where the
creative's code runs:

- **In the visitor's browser.** The request to your API leaves from each visitor's device, from
  their IP address — not from an Epom server. An API that only answers whitelisted IPs therefore
  refuses it. Put a small proxy or cache of your own in front of such a feed (it calls the API
  from your whitelisted server and serves the result publicly), and point the creative at that.
- **Under the bundle's origin.** The `index.html` of a ZIP loads from Epom's file storage or CDN
  host inside the template's iframe, so a `fetch`/XHR is a cross-origin request: the API must
  answer with CORS headers that allow that origin (or `*`). An API without CORS fails in the
  browser console with a CORS error, not in Epom. A creative that is **not** framed — HTML code
  placed with *Without Wrapper* — runs under the publisher's page origin instead, and the
  publisher's own Content-Security-Policy, if their page sets one, applies to it.
- **Over HTTPS.** On an `https` page an `http` API is blocked as mixed content.

Keep secrets out of the bundle: every file is publicly downloadable, so an API key in the ZIP is
readable by anyone. Use a key meant for browser use, or keep the key in your proxy. And plan for
the API being slow or down — show a static fallback rather than an empty frame.

## Make an HTML5 banner responsive (fit the width of the slot)

The frame is as big as the template makes it: the example above uses the banner's
`$$WIDTH$$` × `$$HEIGHT$$`, which is the ad unit you picked. To fill a slot whose width changes
(full width on mobile, a fixed height of 100 px, say), two things are needed:

1. **The template** sizes the frame to the slot — `width="100%"` with a fixed height instead of
   `$$WIDTH$$` — and, on Mobile Site and Non-standard placements, the tag's **Fit container**
   option makes the ad take the size of the element you put the tag in.
2. **The creative** itself is built to stretch (CSS sizes in % or viewport units). A creative
   exported at a fixed 300×250 stays 300×250 inside a wider frame — it is cropped or
   letter-boxed, and only rebuilding it responsive fixes that. Creatives with very different
   proportions (a 492×328 design into a 728×90 slot) cannot be adapted by sizing at all.

## My HTML5 banner is blank, cropped or shows 404 in Preview

| What you see | Usual cause | Fix |
|---|---|---|
| Blank frame or 404 inside the frame | `index.html` is in a folder inside the ZIP, or the page has another name | Re-zip the folder's **contents**; check **View contents** |
| Page shows but images/animation missing | Absolute or local paths, or an external library that did not load | Make paths relative; bundle the library |
| Cropped or not filling the slot | The creative has a fixed size; the frame is the ad-unit size | See [Make an HTML5 banner responsive](#make-an-html5-banner-responsive-fit-the-width-of-the-slot) |
| Clicks open the page but reports show 0 clicks | The click does not go through `$$CLICK_REDIRECT_URL$$` | See [How the click reaches an HTML5 creative](#how-the-click-reaches-an-html5-creative) |
| "Should be a .zip file" / an archive error on save | Wrong file type or an [archive limit](#archive-limits) | Fix the bundle and upload again |

## Options and fields

| Field | What it does | Notes |
|---|---|---|
| Banner type | Set to **Template** | HTML5 has no dedicated type; it rides on Template |
| Template | The HTML5 template to use | Filtered by placement type; active templates only |
| HTML5 Zip Creative property | Uploads and hosts the bundle | Must be a `.zip`; extracted server-side |
| Other template properties | Per-template text/number/select/file fields | Defined by the template |
| Ad unit / Width / Height | Creative size | Feeds `$$WIDTH$$` / `$$HEIGHT$$`; shown on Site/Mobile placements |

For the full template-authoring reference (property types, files, sharing), see
[Create and manage banner templates](https://epom.com/ad-server/docs/guides/advertising/templates.md).

## Corner cases and gotchas

> **Corner case:** **saving the banner with the ZIP field left empty keeps the previously
> uploaded bundle** — an empty file input does not clear it. To replace the creative, pick a new
> ZIP; to remove it, use the field's delete button. This is the standard file-property behavior
> (see [HTML code and Template banners](https://epom.com/ad-server/docs/guides/advertising/banner-html-and-template.md)).

> **Corner case:** a ZIP exported from macOS Finder carries a `__MACOSX/` folder; it is harmless
> and unpacked with the rest, but it counts towards the 1000-file limit.

> **Corner case:** the entry file and every asset must be referenced by **relative** paths inside
> the ZIP. The bundle is served from its own hosted folder, so an absolute path or a hard-coded
> localhost URL from your authoring tool will 404 in production.

> **Corner case:** the property key in the template body resolves to the folder URL **with a
> trailing slash**. Write `$$KEY$$index.html`, not `$$KEY$$/index.html` — the leading slash would
> point above the bundle folder.

> **Corner case:** the ZIP field is a **template property, not a banner field** — if the template
> has no HTML5 Zip Creative property, there is nowhere to upload the bundle.
> Ask whoever manages the template to add one (or use a template that already has one) rather than hunting for a
> zip upload elsewhere on the banner form.

> **Corner case:** the upload needs file storage to be enabled for the network. Where it is not,
> the save fails with an error against the ZIP field — that is a network setup problem, not
> something wrong with your bundle; contact Epom support or your account manager.

> **Corner case:** a property key cannot be a **reserved macro name** — `$$WIDTH$$` and
> `$$HEIGHT$$` are refused when you define the template, because the platform already
> substitutes them. They are still available to use in the body; they just cannot be the key of a
> property you define.

> **Corner case:** HTML5 Zip Creative properties are **not supported on the placement-side native
> adapter templates** — they only work as banner creative properties. Use them on regular
> (General / Content Adapter) templates.

> **Corner case:** editing the template body or properties later affects **every
> banner** built on it once the ad cache reloads, without re-saving each banner. Change the entry
> file name in the body and existing banners must have their ZIPs match, or they break.

## Per-role notes

- **Advertiser** — the stock role cannot create Template banners; send the ZIP to your network
  manager, or ask them to switch Template banners on for your role. With that permission you
  upload the ZIP into the template property on the banner yourself.
- **Network manager** — prepares that template, then traffics banners against it like anyone else.
- **Can view share** — the ZIP field and the other property inputs are disabled; existing files
  stay downloadable and the **View contents** tree still opens.

## Related

- [Reuse creative files with the Media Library](https://epom.com/ad-server/docs/guides/advertising/media-library.md) — upload a ZIP once and pick it for the HTML5 ZIP property of many creatives
- [HTML code and Template banners](https://epom.com/ad-server/docs/guides/advertising/banner-html-and-template.md) — the banner type HTML5 rides on
- [Create and manage banner templates](https://epom.com/ad-server/docs/guides/advertising/templates.md) — building the HTML5 template
- [Macros reference](https://epom.com/ad-server/docs/reference/macros.md) — `$$WIDTH$$`, `$$HEIGHT$$` and property keys
- [Banner types — decision guide](https://epom.com/ad-server/docs/guides/advertising/banners-overview.md)