Convert a page, directory, or entire site into a standalone Progressive Web App (PWA) with a lightweight client-side script and a dynamically generated Data URL Manifest.
1P1A (One Page One App) is a client-side PWA approach that removes the need to create and maintain a static manifest.json file for every page or tool.
Add an OJapp script to the page <head>, and it dynamically generates a Web App Manifest as a data:application/manifest+json URL. Depending on the selected mode, visitors can add an individual page, a directory group, or an entire site to their home screen with its own app name, description, icon, identity, start URL, navigation scope, and install presentation.
The core scripts require no build step, user registration, external API, or server-side manifest generation.
id, start_url, and scope when enabled.OJapp reads its meta tags when the script executes. Place all OJapp meta tags before the script tag.
Make the current page—or a query-configured instance of that page—an app on the user’s home screen.
<!-- Optional settings must come before the script -->
<meta name="ojapp:query" content="true">
<meta name="ojapp:title" content="My Custom Tool">
<meta name="ojapp:icon" content="/icon.png">
<script src="https://ojapp.app/js/ojapp_1p1a.js"></script>
Without optional meta tags, the page URL, page title, and available page icon are used automatically.
Make the entire origin a single unified app.
<script src="https://ojapp.app/js/ojapp_1s1a.js"></script>
By default, id, start_url, and scope use the origin root (/).
Turn a directory such as /dashboard/, /tools/, or /docs/ into its own app under the same origin.
<meta name="ojapp:id" content="/dashboard/">
<meta name="ojapp:start-url" content="/dashboard/">
<meta name="ojapp:scope" content="/dashboard/">
<script src="https://ojapp.app/js/ojapp_1s1a.js"></script>
Each directory group can use a different ID and scope, allowing multiple group apps under one origin without separate manifest files or build pipelines.
Enable query handling with:
<meta name="ojapp:query" content="true">
For example:
/timer/?time=5&mode=down&seconds=on&icon=blue
OJapp includes the current query string in the generated Manifest values for:
idstart_urlscopeThis allows the URL to store an app’s selected state while id distinguishes configured instances and start_url restores that state when the app launches.
Browsers process Manifest fields according to their own platform implementation. In particular, a browser may normalize or remove the query from the processed scope. OJapp still writes the configured query to all three fields and lets the browser perform that normalization.
If your page creates or changes the query after the initial load, navigate to or reload the final query URL before asking the user to add it to the home screen. A History API change alone may not update the URL captured by the iOS Add to Home Screen flow.
OJapp can customize the description and screenshots shown in supported browser install interfaces.
Use ojapp:description when the install interface needs different copy from the page’s search description.
<meta
name="ojapp:description"
content="Install this tool for quick access from your home screen."
>
OJapp uses the following priority:
ojapp:description<meta name="description">description when neither existsThis keeps search-oriented page copy separate from install-oriented messaging.
Use the original unnumbered tag for a single image.
<meta
name="ojapp:screenshot"
content="/images/install.png"
>
Use numbered tags to add up to five images.
<meta name="ojapp:screenshot-1" content="/images/install-1.png">
<meta name="ojapp:screenshot-2" content="/images/install-2.png">
<meta name="ojapp:screenshot-3" content="/images/install-3.png">
If at least one numbered screenshot tag is present, the numbered set takes priority and the unnumbered ojapp:screenshot tag is ignored.
All screenshots in the set should use the same aspect ratio. A 1:1 square image is recommended because it remains easy to view in both desktop and mobile install interfaces. OJapp assigns the selected screenshots to wide on desktop and narrow on Android; the final layout is controlled by the browser.
| Meta Tag | Applies To | Description | Default / Fallback |
|---|---|---|---|
ojapp:title |
1P1A / 1S1A | Sets the app name | 1P1A: page <title>; 1S1A: hostname |
ojapp:description |
1P1A / 1S1A | Sets the Manifest install description | Standard page meta description; otherwise omitted |
ojapp:icon |
1P1A / 1S1A | Sets the app icon URL | Available page icon, then OJapp default icon |
ojapp:screenshot |
1P1A / 1S1A | Sets one install screenshot | Omitted |
ojapp:screenshot-1 through ojapp:screenshot-5 |
1P1A / 1S1A | Sets up to five install screenshots; the numbered set takes priority | Omitted |
ojapp:query |
1P1A / 1S1A | Set to "true" to include the current query in id, start_url, and scope |
Disabled; query removed |
ojapp:id |
1S1A / 1G1A | Sets the Manifest app identity | Origin root |
ojapp:start-url |
1S1A / 1G1A | Sets the URL opened from the home screen | Origin root |
ojapp:scope |
1S1A / 1G1A | Sets the navigation scope | Origin root |
ojapp:exclude |
1P1A / 1S1A | Set to "true" to disable OJapp on the page |
Disabled |
All custom id, start_url, and scope values must resolve to the same origin as the current page.
Query-configured home screen entries have been verified on iPhone. Multiple entries created from the same page can retain different launch states, app names, and icons.
The installed icon can also depend on apple-touch-icon, so pages that dynamically select an icon should set it before the OJapp script executes.
OJapp includes the query in the generated id, start_url, and scope. Chrome may normalize the processed navigation scope according to the Web App Manifest specification. Query-based multi-install identity can vary by browser and platform version, so test the intended behavior on the target Android device.
| Mode | App Unit | Default Identity / Start / Scope | Typical Use |
|---|---|---|---|
| 1P1A | Current page | Current page path | Tools, products, articles, profiles |
| 1G1A | Directory group | Explicit directory path | Dashboards, docs, grouped tools |
| 1S1A | Entire site | Origin root / |
Conventional site-wide PWA |
OJapp FREE provides a simple way to implement the 1P1A (One Page. One App.) and 1S1A (One Site. One App.) PWA design patterns.
For normal use, OJapp FREE is provided through the official hosted scripts at:
https://ojapp.app/
The production OJapp FREE runtime is not distributed as a JavaScript file from this repository.
Reference source code may be provided in this repository as .txt files for learning, research, modification, and independent implementation.
If you simply want to use OJapp FREE, please use the official hosted script described in the documentation.
Unless otherwise noted, source code contained in this repository is licensed under the MIT License.
See the LICENSE file for details.
The MIT License in this repository applies only to source code actually published in this repository.
The hosted OJapp FREE runtime provided from ojapp.app and OJapp PRO are separate from this repository and are not covered by this repository’s MIT License.
OJapp PRO is proprietary commercial software.
1P1A (One Page. One App.) and UDA (User Defined App) are PWA design concepts, not products.
1P1A describes a design approach where the application boundary is defined at the page level rather than the entire website.
UDA extends this idea further by allowing users to define an app through a specific URL state, such as query parameters.
OJapp is an implementation and service built around these concepts.
The MIT License in this repository applies only to the source code published here. It does not apply to the 1P1A or UDA concepts themselves.
Questions, test results, edge cases, and feature requests are welcome in this repository. Reference implementations may differ from the current production version of OJapp FREE and are not intended to track every update to the official hosted runtime.