smartbanner.js: an app banner that runs from meta tags alone
Customisable and lightweight smart app banner for iOS and Android
At a glance
- What is it?
- smartbanner.js renders an Apple-style app banner on both iOS and Android from a block of meta tags, with no JavaScript knowledge required and about 6.6KB minified according to the project. It suits site owners who want a store banner with a working close button, and its GPL-3.0 licence is the decision that needs checking before you ship it.
- Who is it for?
- Adopt smartbanner.js if you want a store banner on both platforms from the same block of meta tags, need the close button to stick for a defined period or a given path, and can comply with GPL-3.0 in the pages that load the script. Do not adopt it if your application assets must stay under a permissive licence, since the library is GPL-3.0, and skip it if a native iOS banner is enough for your traffic.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Configuration lives in meta tags, not in JavaScript
smartbanner.js is a customisable and lightweight smart app banner for iOS and Android. The central design decision is that populating it requires no JavaScript knowledge: you add meta tags and include two files.
This configuration block is the whole setup:
<!-- Start SmartBanner configuration -->
<meta name="smartbanner:title" content="Smart Application">
<meta name="smartbanner:author" content="SmartBanner Contributors">
<meta name="smartbanner:price" content="FREE">
<meta name="smartbanner:price-suffix-apple" content=" - On the App Store">
<meta name="smartbanner:price-suffix-google" content=" - In Google Play">
<meta name="smartbanner:icon-apple" content="https://url/to/apple-store-icon.png">
<meta name="smartbanner:icon-google" content="https://url/to/google-play-icon.png">
<meta name="smartbanner:button" content="VIEW">
<meta name="smartbanner:button-url-apple" content="https://ios/application-url">
<meta name="smartbanner:button-url-google" content="https://android/application-url">
<meta name="smartbanner:enabled-platforms" content="android,ios">
<meta name="smartbanner:close-label" content="Close">
<!-- End SmartBanner configuration -->Then the stylesheet and the script:
<link rel="stylesheet" href="/dist/smartbanner.min.css">
<script src="/dist/smartbanner.min.js"></script>The naming convention is consistent throughout, with a smartbanner prefix on every meta name, a platform suffix such as -apple or -google where the value differs per platform, and a hyphenated path style for multi-word options. That consistency is what makes the library usable by someone who never opens the source.
The package is published on npm as smartbanner.js, with the homepage pointing at the npm listing, and the repository also carries a bower.json, so older build setups can still consume it.
Platform targeting by user agent regex
The banner needs to know who it is talking to, and the project gives you three independent controls that combine in a specific order.
enabled-platforms is the base list, android,ios in the example, and it can be set to none to suppress the banner entirely on a given page. On top of that, exclude-user-agent-regex takes a regular expression matched against user agent strings that should not see the banner, and include-user-agent-regex adds user agents that enabled-platforms would otherwise leave out:
<meta name="smartbanner:exclude-user-agent-regex" content="^.*My Example Webapp$"><meta name="smartbanner:enabled-platforms" content="none">
<meta name="smartbanner:include-user-agent-regex" content="iPhone 7">The documented precedence is worth stating precisely, because it is easy to get wrong. include-user-agent-regex only adds to what enabled-platforms allows and never narrows it, so to show the banner to matching agents only, you disable all platforms alongside it. And the three options can be defined at the same time: the banner is shown when either enabled-platforms or include-user-agent-regex matches, unless exclude-user-agent-regex matches, which always takes precedence.
That last rule is the one to remember. An exclusion always wins, so a specific exclusion regex can veto a platform that would otherwise be enabled.
The documentation gives the reasons this exists: an app available only for some Android or iOS versions, an app that is iPhone only and not iPad, or a web app that also serves the same website and should not advertise the native one.
The close button writes cookies, and the cookie scope is configurable
Most hand-rolled app banners reappear on the next page view because nobody implements the dismissal. smartbanner.js treats the close button as a state change: closing the banner sets a cookie that keeps it closed.
By default that cookie lasts for the remainder of the browser session. The hide-ttl option replaces that with a fixed duration in milliseconds, and the documentation gives ten seconds as the example:
<meta name="smartbanner:hide-ttl" content="10000">Scope is configurable too. Once closed, the banner stays closed site-wide by default, which is described as equivalent to hide-path being set to /. You can narrow that to a single path:
<meta name="smartbanner:hide-path" content="/shop">In that case the banner remains closed under /shop only, and only when the user actually closed it, meaning it reappears elsewhere on the site.
For a documentation-driven site, the site-wide default is often wrong and the path variant is the useful one, because a visitor who dismisses the banner on a pricing page does not expect it to vanish on the documentation pages as well. The important detail is that the path-scoped suppression still requires an explicit close, which keeps the banner available for anyone who did not dismiss it.
Custom design works through wrapper classes, not a config file
Styling is handled by a custom design modifier, which is a string added as a class on the banner wrapper. The wrapper already gets an automatically generated smartbanner--<platform> class, such as smartbanner--ios or smartbanner--android, and the modifier adds a second class alongside it.
With an externally defined style, the modifier carries your own name:
<meta name="smartbanner:custom-design-modifier" content="mysite.com">which adds smartbanner--mysite.com to the wrapper, letting your own stylesheet take over while the library keeps doing the behaviour.
With a platform name as the modifier, the effect is the opposite. Setting it to ios adds smartbanner--ios to the wrapper regardless of the actual platform, which forces the iOS styling on every device:
<meta name="smartbanner:custom-design-modifier" content="ios">That second form is the more interesting one. It is how a site that has tuned the iOS look can present the same design to Android users, at the cost of the platform distinction that the library otherwise maintains, including the platform specific app icon and the View button.
Button labels can also differ per platform, through smartbanner:button-apple and smartbanner:button-google, which lets the call to action name the store rather than use a single generic label.
Automatic injection versus the API mode
By default the banner is added to the DOM automatically. If you need control over when and where that happens, the api meta tag switches it to manual mode:
<meta name="smartbanner:api" content="yes">The API mode is also the hook for the events the library emits for API implementations, which is listed as a feature in its own right. Events give you a way to react to the banner lifecycle, which matters when the banner sits inside a single page application where a server-rendered banner would be out of place.
Positioning can be taken over as well. The disable-positioning option turns off the built-in positioning so you can place the banner yourself in CSS, which is the escape hatch for a layout where a fixed top bar would collide with an existing sticky header.
The whole feature list adds up to a coherent position on the library. The stated advantages are that no JavaScript knowledge is needed to populate it, that it mimics the default Smart App Banner design Apple documents, that the information is customisable with internationalisation support, and that the code is pure JavaScript at 6.6KB minified, with an ECMAScript 6 source.
Building the dist files with esbuild and sass
The repository ships built files in a dist/ directory, and the build is driven by npm scripts in package.json. The JavaScript bundle is produced with esbuild targeting es2015, and the stylesheet is compiled from sass:
"build:js": "esbuild src/index.js --bundle --target=es2015 --outfile=dist/smartbanner.js",
"build:js-min": "esbuild src/index.js --bundle --target=es2015 --minify --outfile=dist/smartbanner.min.js",
"build:css": "sass src/smartbanner.scss dist/smartbanner.css",
"build:css-min": "sass --style=compressed src/smartbanner.scss dist/smartbanner.min.css",
"build": "npm run build:js-min && npm run build:css-min && npm run bannerise",Those lines are copied from the scripts section of the package manifest, and they show the structure of the build. The non-minified and minified variants are produced separately so you can serve either, and the final build step runs a bannerise script that applies a template from banner.tmpl to the four built files, which is how the licence header and other notices get into the distributed artefacts.
The package metadata shows the shape of the project. The version is 1.30.0, the package is an ES module, main points at dist/smartbanner.js and style at dist/smartbanner.css, and the engines field requires Node 22 or newer. The development dependencies are modest and mostly testing related: mocha and chai, jsdom for a DOM environment, c8 for coverage, eslint, sass and esbuild, plus a local-web-server for manual testing and an add-banner helper from the same author.
There is also a bower.json for the older distribution path, a .tern-project file, and eslint configuration at the root, so the project has a conventional modern JavaScript layout.
GPL-3.0 is the adoption decision, and there are no releases
The licence is the thing to think about hardest. The package manifest declares GPL-3.0, and the LICENSE file at the repository root is the GNU General Public License. The project is distributed on npm and bower under that licence, and the bannerise step exists to carry the notices into the built files.
GPL-3.0 is copyleft. A front-end asset is unusual territory for it, because a script linked into a page is not a separate binary you can keep to yourself, and a licence review has to decide how the obligations apply to the site that loads the file. That is a question for your own legal counsel rather than one to resolve from this repository, and the point to raise is that the whole library is GPL rather than a small permissively licensed core with an optional GPL add-on.
On maintenance, the repository is not archived and the last push was on 2026-10-20, which is recent work. There are no GitHub releases, so the npm version at 1.30.0 is the reference point rather than a set of tagged artefacts, and the repository also carries SECURITY.md, CONTRIBUTING.md, a code of conduct and an issue template, which are the markers of a maintained community project.
One last practical note. The library renders a banner that imitates Apple's design, and the design reference in the documentation points at Apple's own Smart App Banner documentation. A site that only needs the native iOS behaviour may not need this script at all, and the case for the library is strongest on the Android side and wherever the close behaviour and cross-platform labelling matter.
Editorial conclusion
Adopt smartbanner.js if you want a store banner on both platforms from the same block of meta tags, need the close button to stick for a defined period or a given path, and can comply with GPL-3.0 in the pages that load the script. Do not adopt it if your application assets must stay under a permissive licence, since the library is GPL-3.0, and skip it if a native iOS banner is enough for your traffic. Before you ship it, verify that the bundled dist files match the version you pinned, check that the banner behaves acceptably on your target devices, and confirm your hosting and bundling setup satisfies the GPL obligations the licence creates for the pages that include it.
Frequently asked questions
How do I add smartbanner.js to a site?
Add the smartbanner meta tags for the title, author, price, icons, button text and URLs, then include the compiled stylesheet and script from the dist directory, for example /dist/smartbanner.min.css and /dist/smartbanner.min.js. No JavaScript knowledge is required to configure it.
How do I hide the smartbanner for specific devices or pages?
You can set enabled-platforms to none to suppress it on a page, and use exclude-user-agent-regex to match user agents that should not see it. The exclusion always takes precedence, while include-user-agent-regex only adds agents on top of what enabled-platforms allows.
How long does the smartbanner stay closed after a user clicks the close button?
By default it stays closed for the remainder of the browser session, because closing sets a session cookie. The hide-ttl option replaces that with a fixed duration in milliseconds, and hide-path can narrow the scope to a single path such as /shop instead of the whole site.
Can I restyle the smartbanner or control its position?
Yes. The custom-design-modifier option adds a class to the wrapper, either your own class name for external styles or a platform name such as ios to force that platform's styling everywhere. The disable-positioning option turns off the built-in positioning so you can place the banner yourself.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ain-smartbanner-js)Was this useful?