Skip to content

Smart Banner Script

The smart banner script (banner.js) is a standalone embed for showing app install banners on customer websites. No npm install, no build step, just a script tag. It is the simplest way to add a smart banner to a marketing site, blog, or static page.

For programmatic control inside an SPA or framework, use the Web SDK instead.

<script src="https://your-app.tolinku.com/banner.js" async></script>

Replace your-app.tolinku.com with your Appspace’s domain. The script auto-detects iOS and Android devices, fetches your active banner config, and renders the highest-priority banner. Desktop visitors are ignored.

Every option is set as a data-* attribute on the script tag. All attributes are optional. When omitted, sensible defaults are used.

AttributeValuesDefaultDescription
data-positiontop, bottomserver config or topBanner edge
data-stylepinned, floating, stackedpinnedPinned (fixed overlay), floating (rounded fixed card), or stacked (sticky in document flow above the page header)
data-anchorCSS selector(auto-detect)Stacked mode only: explicit element to inject before. Auto-detects header, nav, [role="banner"], .header, #header, .navbar when omitted
data-animationslide, fade, pop, noneslideEntrance animation
data-themelight, darklightColor preset (overridden by dashboard config)
data-labelstring(any)Show only banners with this label
data-delay0600000Delay display by N milliseconds
AttributeValuesDescription
data-bghex colorBanner background
data-borderhex colorBorder color (omit for none)
data-radius024Banner corner radius (floating only)
data-margin024Edge margin in pixels (floating only)
data-shadownone, sm, md, lgShadow preset
AttributeValuesDescription
data-title-colorhex color
data-title-size1024Pixels
data-title-weight400, 500, 600, 700
AttributeValuesDescription
data-body-colorhex color
data-body-size1020Pixels
data-body-weight400, 500, 600, 700
AttributeValuesDescription
data-cta-bghex colorDefaults to title color (auto-invert)
data-cta-colorhex colorDefaults to banner background (auto-invert)
data-cta-size1018Pixels
data-cta-weight400, 500, 600, 700
data-cta-radius01000 = square, 100 = pill
AttributeValuesDescription
data-icon-size2464Pixels
data-icon-radius032Pixels

Boolean attributes. Add the attribute to enable; omit to disable.

AttributeEffect
data-hide-iconHide the app icon
data-hide-closeHide the close button (banner cannot be dismissed)
data-hide-bodyHide the description line, show only the title
AttributeDescription
data-classAdds the value as a class on the banner container, so you can target it with your site’s CSS for advanced styling
<script src="https://your-app.tolinku.com/banner.js" async></script>
<script
src="https://your-app.tolinku.com/banner.js"
data-style="floating"
data-theme="dark"
data-animation="pop"
async
></script>
<script
src="https://your-app.tolinku.com/banner.js"
data-style="floating"
data-bg="#3B82F6"
data-title-color="#ffffff"
data-body-color="#dbeafe"
data-cta-bg="#ffffff"
data-cta-color="#3B82F6"
data-radius="16"
data-shadow="lg"
async
></script>
<script
src="https://your-app.tolinku.com/banner.js"
data-hide-body
data-hide-icon
data-style="floating"
async
></script>
<script
src="https://your-app.tolinku.com/banner.js"
data-position="bottom"
data-delay="2000"
async
></script>

Every styling value resolves through this chain. The first non-empty source wins:

  1. The data-* attribute on the script tag
  2. The banner config set in your Tolinku dashboard
  3. The active theme’s value
  4. A built-in fallback

So a data-bg="#000" on the script tag overrides whatever color you set in the dashboard, which overrides whatever the theme would have provided, which overrides the built-in white.

PinnedFloatingStacked
Positionposition: fixed viewport overlayposition: fixed viewport overlayposition: sticky in document flow
EdgesEdge-to-edge across the viewportMargin from each edgeEdge-to-edge
CornersSquareRounded (configurable)Square
Layout impactPushes body content down via paddingOverlays content (no body push)In flow, naturally pushes the page header down
Plays nicely with the host site’s fixed header?No, overlaps itNo, overlaps itYes, the host header gets pushed down
data-radius / data-marginIgnoredUsedIgnored
  • Pinned: simple sites without a fixed header. The banner overlays the very top of the viewport.
  • Floating: marketing pages or hero sections where the rounded card aesthetic fits.
  • Stacked: any site that already has its own fixed or sticky header. Stacked injects the banner above that header in the DOM so it doesn’t overlap navigation.

When data-style="stacked", the script injects the banner element into the page DOM as a sibling of (and above) the host site’s header element. The banner uses position: sticky; top: 0 so it stays at the top of the viewport while the user scrolls.

The script tries the following in order, using the first match it finds:

  1. The data-anchor="<selector>" attribute, if provided.
  2. The first <header>, [role="banner"], <nav>, .header, #header, or .navbar in the document.
  3. Falls back to inserting as the first child of <body>.

For data-position="bottom", the same logic applies but with <footer>, [role="contentinfo"], .footer, #footer, and the banner is inserted after the anchor (or as the last child of <body>).

<!-- Auto-detect (most common) -->
<script src="https://your-app.tolinku.com/banner.js" data-style="stacked" async></script>
<!-- Explicit anchor when auto-detect picks the wrong element -->
<script
src="https://your-app.tolinku.com/banner.js"
data-style="stacked"
data-anchor="#site-header"
async
></script>

Caveat: the host site’s header is itself position: fixed

Section titled “Caveat: the host site’s header is itself position: fixed”

If the host site’s header uses position: fixed; top: 0 (rather than position: sticky or no positioning), the banner can’t push it down via document flow because fixed elements are out of flow. The banner will sit above the header in the DOM but the header still renders at viewport top:0 over the banner area. The fix in that case is for the site to add its own offset — e.g. header { top: 56px; } while the banner is mounted, or to switch the header from fixed to sticky.

Caveat: the host site uses a custom scroll container

Section titled “Caveat: the host site uses a custom scroll container”

position: sticky only works when the page scrolls on the document (the default). If the host site uses a wrapper div with overflow: auto as the scroll container (some app-style layouts), the banner sticks to the document, not to the wrapper, so it scrolls out of the wrapper’s viewport. Either switch to pinned/floating mode for those sites, or move the script tag inside the scroll container itself if your build allows.

Because stacked mode injects an in-flow element, the page’s content shifts down by the banner height when the banner appears (and shifts back up when dismissed). The slide animation runs immediately after, so the perceived effect is “content shifts, banner slides in” with about a one-frame gap. Acceptable for a banner that loads on page open; if you need a perfectly smooth entrance, use floating instead, which overlays without reflowing.

  • slide is the safe default and works in both pinned and floating modes.
  • fade and pop are best paired with data-style="floating". In pinned mode, pop silently downgrades to slide because a center-origin scale clips visually against the viewport edge.
  • none removes both the entrance and exit transition. Use this when the banner needs to appear on a tightly-controlled UI (for example, inside an existing animation timeline).

If you have multiple banners configured, use data-label to show a specific one on a specific page:

<!-- On the marketing homepage -->
<script src="..." data-label="website" async></script>
<!-- On a campaign landing page -->
<script src="..." data-label="promo" async></script>

Without data-label, the highest-priority active banner is shown.

When a visitor closes the banner, the dismissal is stored in localStorage for the number of days configured in the banner’s dismiss_days setting. Subsequent visits within that window will skip the banner and show the next one in the priority list.

The script targets evergreen mobile browsers (Safari iOS 12+, Chrome Android 70+). It uses fetch, URL, URLSearchParams, localStorage, and requestAnimationFrame. The script returns early on desktop and on user agents it cannot match to iOS or Android, so there is no impact on desktop visitors.

  • All color values are sanitized (control characters and CSS-injection sequences are stripped) before being inserted into the rendered <style> tag.
  • The CTA href is validated to be http: or https: only. Other protocols, including javascript:, are rejected.
  • The data-class value is stripped to a safe character set ([a-zA-Z0-9_-\s], max 100 characters).
banner.js@tolinku/web-sdk
Install<script> tagnpm install
Configurationdata-* attributesTyped options object
When to useMarketing sites, static pages, no build stepSPAs, frameworks, programmatic control
Bundle sizeSingle ~12 KB scriptTree-shakeable npm package
Banner featuresFull v1.2 feature setSame options as banner.js v1.2

The two paths render identical-looking banners. Pick whichever fits your stack.