# Appwright Push - Notify Your Users

> Send a notification to every installed copy of your Appwright app from a web dashboard.

- **Applies to:** Appwright
- **Source:** the Integration Guide shipped inside the app; this page is generated from it.
- **HTML:** https://freewebsitetoapk.com/docs/appwright-push

Send notifications to everyone who installed your app, straight from Appwright on your own Firebase project - schedule, edit after sending, cancel, deep links

### 1. How It Works

Appwright Push sends notifications to everyone who installed your app, from inside Appwright - send now, schedule, edit after sending, cancel, deep links.

Every message can be designed: 8 templates, your own colour, up to 3 buttons that each open their own page, sound and pop-up choices, and a native in-app banner, card, sheet or full screen while the app is open. A live preview shows it exactly as users' phones will.

It runs on YOUR OWN Firebase project: your users, your project, no shared limits, and nothing of yours hosted by Appwright. Firebase Cloud Messaging is free with no message limit.

You need two files from that project - google-services.json (for the build) and a service-account key (for sending). The next steps get both. (iOS is separate and unchanged: your APNs key via 'iOS push setup' in Notifications.)

Appwright Push and OneSignal are alternatives: turning one on turns the other off.

### 2. Create a Firebase Project

Go to Firebase Console and click 'Add project' (or open a project you already have). A free Firebase project is enough - no billing needed for notifications.

One project can hold several of your apps.

[Open Firebase Console](https://console.firebase.google.com)

### 3. Add Your App and Download google-services.json

In your Firebase project:

- Click 'Add app' and choose Android
- Enter the package name EXACTLY as set in the Appwright wizard (e.g. com.yourname.yourapp) - a mismatch means notifications never arrive, and Appwright refuses the build for it
- Click 'Register app' and download google-services.json
- You can skip the remaining SDK steps - Appwright handles them

### 4. Turn It On and Upload the File

In the build wizard's Push Notifications card:

- Enable 'Appwright Push'
- Tap 'Upload google-services.json' and pick the file from the previous step

The wizard checks the file contains your package name. Then build your APK as normal - during the build your app is registered for push against your project.

Users just install the app and open it once. On Android 13+ they are asked to allow notifications after the first screen loads.

Templates, buttons and in-app styles need an app built with this version of Appwright or later. An older build still receives every message - it shows it in the plain style it always did.

### 5. Upload Your Service-Account Key (Once)

Appwright sends through your project, so it needs a key from it - the same file OneSignal asks for.

In Firebase Console:

- ⚙ Project settings → 'Service accounts' tab
- Click 'Generate new private key' and confirm - a JSON file downloads

In Appwright: Home > Tools > Notifications → pick your app → 'Upload key' → choose that JSON.

Appwright verifies the key with a test send to your project before storing it (encrypted), so a green tick means the next send will really go out. One upload per app; rebuilding the app does not need it again unless you switch Firebase projects.

⚠️ Upload the SERVICE-ACCOUNT key here, not google-services.json - the screen tells you if you mix them up. To revoke access later, delete the key in Firebase Console.

### 6. Send Your First Notification

In Home > Tools > Notifications:

- Pick your app
- Write a title (message, image and link are optional)
- Check the Live preview card
- Tap 'Send notification'

Every phone with your app installed receives it.

For the image, paste an https:// link or tap 'Choose image from device' (up to 2 MB, PNG, JPEG or WebP). A picked image is uploaded only when you press Send - you can pick, replace or remove it as often as you like first.

### 7. Pick a Template

Design → Template sets the notification's layout. The text always comes first - a picture never covers the message:

- Automatic - Image card when the message has an image, otherwise Standard
- Standard - title and the whole message; an image becomes a small thumbnail beside it
- Image card - the picture BELOW the readable title and message
- Banner - a card filled with your colour, with an optional badge
- Promo - a badge such as '50% OFF' and a coloured button (your first button)
- List - up to 6 short lines, e.g. several order updates
- Countdown - a live timer that counts down to a date and time you pick, then leaves the tray by itself
- Progress - a progress bar; edit & resend with a new value and the bar moves on every phone without buzzing again
- Minimal - title and one line, no sound, no pop-up

Text and image sizes adapt to each user's font size, so nothing gets cut off on phones with large text.

### 8. Choose a Colour

Design → Colour tints the notification's icon, banner, buttons and countdown. Pick one of the 9 ready colours, or '+' for any #RRGGBB.

Every ready colour reads well on both light and dark phones. A custom colour is checked against both: if it is too pale or too dark, the note under the colours says so, and 'Fix contrast' in the custom-colour box nudges it to the nearest shade that works while keeping its hue. Text on a coloured button or banner is inked black or white automatically.

Use the 'Light phone' / 'Dark phone' switch in the Live preview to see both.

### 9. Add Buttons

Design → Buttons: '+ Add button' (up to 3). Each has a label (up to 24 characters) and its own link - e.g. 'Track order' → #/orders/1042 and 'Help' → #/support. Leave a button's link empty to open the main link.

Buttons show under the notification in the tray and in the in-app presentation. In the Promo template the first button becomes the big coloured button on the card.

### 10. While the App Is Open

Design → 'While the app is open' decides what a user sees when the message arrives while they are using your app:

- App's own design (default) - your app's code shows it (see In-App Inbox below)
- Top banner - slides down from the top and hides itself after a few seconds
- Centre card - a card over the dimmed app with the image, text and buttons
- Bottom sheet - the same card rising from the bottom
- Full screen - a large image with the buttons at the bottom

The presentation follows the phone's light or dark theme, and Back or tapping outside closes it. When it is shown, the same message is not also put in the tray - the user is already looking at it.

With 'In-app message only' (Delivery → Show as), a message that arrives while the app is closed is shown the next time the user opens it.

### 11. Sound, Pop-up and Timing

Design → Behaviour:

- Sound - off for a silent notification
- Pop up on screen - off to skip the peek over whatever the user is doing (it still lands in the tray)
- Auto-dismiss - removes the notification from the tray after 30 seconds up to 3 days (Android 8 and newer)

Advanced options:

- Icon / avatar image - a round picture beside the text (https:// link)
- Bundle key - messages sharing it are grouped under one heading
- Replace key - a newer message with the same key REPLACES the older one on the phone and in the inbox, e.g. a live score

Users can also tune sound per type in Android's notification settings for your app.

### 12. Test, Save and Reuse

- Live preview - Collapsed, Expanded and In-app tabs, on a light or dark phone, drawn by the same code your users' phones run
- 'Test on this phone' - shows the message on YOUR phone only, as a real notification or as the in-app presentation over the Notifications screen. Nothing is sent to users
- Saved templates (book icon at the top) - 'Save the current message as a template' keeps the text, link, image and every design choice on this phone; 'Use' loads it back in one tap
- In History, 'Duplicate as a new message' starts a new message from any earlier one

### 13. Schedule for Later

In the Delivery card, tap the 'When' row and choose 'Schedule for later...', then pick a date and time. The notification goes out automatically at that moment.

Until it fires, you can edit or cancel it from the History list below.

### 14. Fix a Mistake After Sending

Tap any notification in History:

- 'Edit & resend' - loads it back into the composer with its whole design; 'Update & resend' then replaces it IN PLACE on every device
- 'Cancel' - removes it from every phone where it has not been opened yet, including an in-app presentation still on screen
- 'Delete' - same as cancel, and clears it from your history

⚠️ A notification the user already opened or dismissed cannot be taken back.

### 15. Open a Specific Page

The optional Link field controls what a tap opens (each button can have its own):

- A full https:// address
- An in-app route like #/offers

Your app's code can also read it any time:

```
const link = window.WebToApk?.getLaunchUrl?.();
window.addEventListener('appmint:deep-link',
  e => goTo(e.detail.url));
```

### 16. In-App Inbox (Optional)

Every push is also stored inside the installed app (last 50), so your app can show its own notifications screen with unread badges. This works in EVERY build mode - including website (URL) apps, where you just add these few lines to your own site.

When the shell already showed a message on screen (a style under 'While the app is open'), the event says presented: true - do not draw a second banner then. An app that draws all its own banners can turn the shell's off with setPushPresentation('none').

Dismiss is a SWIPE, not a tiny ✕, and it is reversible - pair it with a brief Undo:

```
const B = window.WebToApk;
const inbox = JSON.parse(B?.getPushInbox?.() ?? "[]");
// [{id,title,body,imageUrl,link,receivedAt,read,
//   template?,accent?,buttons?,badge?,inapp?...}]
const unread = inbox.filter(m => !m.read).length;

// live arrival while the app is open
window.addEventListener('appmint:push', e => {
  const d = e.detail;
  if (d.type === 'received' && !d.presented) showBanner(d.message);
  refreshInbox();   // fires for 'revoked' too
});

B?.markPushRead?.(id);        // "" = mark all read
B?.dismissPushMessage?.(id);  // swipe away
B?.restorePushMessage?.(id);  // ...Undo
B?.setPushPresentation?.('none'); // app draws its own
```

### 17. If Nothing Arrives on Your Test Phone

Almost always a limit on the TEST PHONE, not your app or your users.

Android allows roughly 100 push registrations per phone. Every FRESH install of an app that uses notifications takes one - so installing build after build while testing can use them all up, and that phone then stops receiving for newly installed apps.

Free up slots (this is what actually works):

- Uninstall test apps you no longer need - Android releases the slot each one was holding
- Or clear a test app's data: Settings > Apps > [that app] > Storage > Clear data - that releases its slot without uninstalling
- On an emulator, wiping it resets every slot at once

Restarting the phone does NOT help: these registrations are stored permanently, which is why they survive a reboot. Clearing Google Play Services' cache does not free them either.

Avoid it while testing:

- Keep ONE package name while you iterate - every different package name takes its own slot
- Install the new APK OVER the old one instead of uninstalling first - an update keeps the existing registration, a reinstall spends a new one
- Test on a spare phone or an emulator; wiping an emulator resets its slots instantly
- Delete test apps you have finished with

Also check the basics: the app was opened at least once after installing, and notifications are allowed for it in Android settings. The app re-subscribes on every launch, so it recovers by itself once slots free up - no rebuild needed.

### 18. Limits and Good Practice

- No limit on how many notifications you send - Firebase Cloud Messaging is free
- Title up to 120 characters, message up to 1000; image and icon links must be https://
- Up to 3 buttons (24-character labels) and up to 6 list lines
- On the free plan a short ad plays before each send
- Test apps: remove them with the trash icon next to the app selector - this deletes the history and stored keys in Appwright only; your Firebase project is untouched, and a rebuild adds the app back
- Rebuilding with a NEW google-services.json from the SAME project changes nothing: your key stays, existing installs keep receiving
- ⚠️ Moving the app to a DIFFERENT Firebase project is a clean break. Rebuild with the new google-services.json, upload the new project's key (Appwright drops the old one, since it could never send for the new project) - and know that phones still running the OLD version stop receiving until their users update. Notifications reach a project, and those installs are still listening to the old one
- Send sparingly: users uninstall apps that spam them

### 19. Choose Who Gets It

Under 'Who gets it', a message goes to Everyone (the default) or to the phones you choose:

- Countries, languages, Android versions and app versions
- Activity - opened the app in the last N days, or has not opened it for N days
- Only phones where notifications are turned on
- User IDs and tags that your app's page sets (next step)

Before you send, the screen shows how many phones your choice reaches.

More ways to send:

- Each phone's local time (under When) - e.g. 09:00 on every phone's own clock, time zone by time zone
- A/B test - write a version B; each version goes to a test share of the audience, and after the wait you set, the one with more opens (or taps) goes to everyone else
- Daily limit per phone - the most messages one phone gets from this app in a day; messages over it are skipped for that phone and shown as 'skipped (daily limit)'

History shows, for each message, how many phones it went to, how many failed and how many were skipped.

⚠️ Choosing who, local time, A/B tests, automations and the daily limit reach only phones running an app built from 30 Sep 2026 on (they register themselves). Phones on older builds still get 'Everyone' sends - rebuild and publish an update to reach them this way too.

Android only: these choices never reach iPhone installs.

### 20. Target Signed-In Users and Tags

Your app's page tells Appwright Push who is signed in and what to know about this install. Then you can send to one user, or to everyone with a tag such as plan = pro.

- setPushUser - after sign-in, with YOUR OWN account id (the database id, never an email address or phone number). Letters, digits and _ @ . : + - (up to 128). Call it with "" on sign-out, or the phone keeps getting that user's messages
- setPushTag / setPushTags - a tag name (letters, digits and _, up to 32) and a value (up to 128). "" removes a tag; up to 50 per install
- getPushUser / getPushTags - read back what this phone holds

IDs and tags belong to the install, not to the account: clear user-specific tags on sign-out too. The phone reports a change a few seconds later (on the next launch when it is offline). The same user signed in on two phones is reached on both.

Android only: an iPhone build has no setPushUser or tags.

```
const B = window.WebToApk;

// after sign-in: your own account id
B?.setPushUser?.(user.id);
B?.setPushTag?.('plan', user.isPro ? 'pro' : 'free');
B?.setPushTags?.(JSON.stringify({ city: 'pune', level: '12' }));

// on sign-out
B?.setPushUser?.('');
B?.setPushTag?.('plan', '');

// read back
const who = B?.getPushUser?.() ?? '';
const tags = JSON.parse(B?.getPushTags?.() ?? '{}');
```

### 21. Automations

Messages that go out by themselves. In Automations, tap '＋ New' and pick one:

- Welcome - N minutes after a new install (from 0 minutes to 30 days). Each phone gets it once
- Win-back - when someone has not opened the app for N days (1 to 180). Once per absence: a phone that comes back and stays away again gets it again
- Tag - N minutes after your app's page sets a tag, optionally only for one value. It goes out only if the tag is still set when the time is up

Abandoned cart: set a tag when items go into the cart and remove it at checkout. A 'cart' automation with a 60-minute delay then reminds only the people who left without buying. Setting the same value again does not restart the clock; after the tag is removed, setting it again can send once more.

Automations count towards the daily limit per phone, and reach phones on builds made from 30 Sep 2026 on.

Android only: automations never reach iPhone installs.

```
const B = window.WebToApk;

// items added to the cart
B?.setPushTag?.('cart', 'open');

// checkout finished, or the cart emptied: no reminder
B?.setPushTag?.('cart', '');
```

### 22. Reach Users With Notifications Off

A phone where notifications are turned off never shows a tray notification - but your message still reaches the app, and an in-app message appears the next time the user opens it. Use that to ask them to turn notifications back on:

- Who gets it → Choose who → turn on 'Notifications off'
- Show as → In-app only (a Top banner or Centre card under Design)
- Design → Buttons → '+ “Turn on notifications” button'. Its link is appmint://notifications/enable: a tap shows the permission prompt, or opens the app's notification settings when the prompt can no longer be shown

When the app has phones with notifications off, the send center shows 'Reach the N phones with notifications off' under the Firebase key - one tap sets all three. As soon as a user turns notifications on, their phone leaves that audience.

The button needs an app built with this version of Appwright or later; older builds treat the link as an ordinary link. appmint://notifications/settings opens the settings screen directly.

```
// Your page can offer the same thing itself:
const r = await window.AppMint?.enableNotifications?.();
// r = { state: 'granted' | 'prompt' | 'blocked' | 'unavailable',
//       changed, openedSettings }

// and hear a push button's result too:
window.addEventListener('appmint:notifications', e => {
  if (e.detail.state === 'granted') hideNotifBanner();
});
```

