SuperView Push
Send notifications to your app from a dashboard, from your own server, or automatically when an order changes in your store. Through your own Firebase project, with no push bill.
What you get
- A dashboard on your app's page to write a notification, choose who gets it, preview it on a phone, and send it now or later.
- A server API, so your own system can send a notification to one customer or to everyone.
- Webhook connectors for Shopify, WooCommerce and anything else that can send JSON, so customers hear about their order without you lifting a finger.
- A few lines of JavaScript for your website, to ask people to subscribe and to say who is signed in.
There's no monthly fee from us and no per-message price. Notifications go through Firebase Cloud Messaging in your own Firebase project, which Google offers for free.
Setup
- Your app needs the SuperView Push (Firebase) add-on, which adds Firebase Cloud Messaging. If it doesn't have it, switch it on in the builder; you pay only for that add-on.
- Create a free project in the Firebase console, add your app to it, and upload its config file (
google-services.jsonfor Android,GoogleService-Info.plistfor iOS) on your app's page. - For iPhone: create an APNs authentication key in your Apple Developer account and upload it in Firebase under Project settings → Cloud Messaging. Without it, only Android phones get notifications.
- In Firebase, open Project settings → Service accounts → Generate new private key. Upload that file under Push notifications → Settings on your app's page.
- Ask people to subscribe from your website (see below). Nobody gets notifications until they say yes on their phone.
Dashboard
Open My apps, choose your app, then Open push dashboard.
- Send: title (up to 120 characters), message (up to 1000), an optional image and page to open. Choose everyone or people who match filters, and see how many phones match before you send. Send now, schedule it, or save a draft.
- History: every notification with how many phones it targeted, how many Firebase accepted, and how many people opened it. Cancel a scheduled one, or send or delete a draft.
- Subscribers: each phone with its user ID, email, tags, app version and when it last opened the app. Search by any of them.
- Webhook connectors: create, test and switch off the automatic notifications described below.
- Settings: your Firebase service account and your server API key.
Website (JavaScript)
Inside your app, your website can use SuperView.push. Every call returns a Promise. It only exists when the page is opened in your app, not in a normal browser, so check for it first.
SuperView.push.subscribe()Asks for permission and registers the phone. Resolves { subscribed, deviceId }.SuperView.push.unsubscribe()Stops notifications to this phone. Resolves when done.SuperView.push.isSubscribed()Resolves true or false.SuperView.push.getStatus()Resolves { subscribed, permission, deviceId, externalUserId, email, tags }.SuperView.push.setExternalUserId(id, hash)Links the phone to your user ID. hash is optional unless you require identity verification. Pass null when they sign out.SuperView.push.setEmail(email, hash)Links the phone to an email address. hash is optional unless you require identity verification. Pass null to clear it.SuperView.push.setTag(key, value)Saves a label you can target, such as plan = pro.SuperView.push.removeTag(key)Deletes that label.A subscribe button
<button id="notify-me">Get order updates</button>
<script>
document.getElementById('notify-me').addEventListener('click', async function () {
if (!window.SuperView || !SuperView.push) {
return;
}
try {
const status = await SuperView.push.subscribe();
if (status.subscribed) {
await SuperView.push.setTag('updates', 'orders');
}
} catch (error) {
console.warn('Notifications are not available', error);
}
});
</script>When someone signs in or out
Set the same ID your store or server uses for that customer, so you can reach them by ID or email later. The second argument is the hash described under Identity verification; leave it out only while verification is off.
SuperView.push.setExternalUserId('1042', '<hash of 1042 from your server>');
SuperView.push.setEmail('[email protected]', '<hash of [email protected] from your server>');
SuperView.push.setExternalUserId(null);
SuperView.push.setEmail(null);Identity verification
Your app id is public, because it ships inside your app. Without verification, anyone who knows it could tell us “this phone belongs to user 1042” and receive that customer's order notifications. Identity verification stops that: your server signs each user ID and email, and we only link a phone to a customer when the signature matches.
- On your app's push dashboard, open Settings → Identity verification and copy the identity secret. Keep it on your server only.
- On your server, make the hash: the hex HMAC-SHA256 of the value, with the identity secret as the key. For an email, trim spaces and lowercase it first.
- Pass the hash as the second argument:
setExternalUserId(id, hash)andsetEmail(email, hash). - Once your website sends hashes, switch on Require verification. From then on, a user ID or email without a valid hash is refused.
PHP
$secret = getenv('SUPERVIEW_IDENTITY_SECRET');
$idHash = hash_hmac('sha256', (string) $user->id, $secret);
$emailHash = hash_hmac('sha256', strtolower(trim($user->email)), $secret);Node.js
const crypto = require('crypto');
const secret = process.env.SUPERVIEW_IDENTITY_SECRET;
const sign = value => crypto.createHmac('sha256', secret).update(value).digest('hex');
const idHash = sign(String(user.id));
const emailHash = sign(user.email.trim().toLowerCase());Replacing the secret in Settings breaks every hash made with the old one until your server uses the new secret, so update both together.
Server API
Create a key under Push notifications → Settings. It's shown once; keep it on your server, never in your website's code. Send it with every request:
Authorization: Bearer svp_…POST https://api.superview.app/api/push/v1/notificationsSend now, or later with sendAt.GET https://api.superview.app/api/push/v1/notifications/:idStatus and counts of one notification.DELETE https://api.superview.app/api/push/v1/notifications/:idCancel a scheduled notification.Send to one customer
externalUserIds, emails and tags are shortcuts. They narrow the audience you give, and when you use several they must all match.
{
"title": "Your order has shipped",
"body": "Order #1001 is on its way.",
"launchUrl": "https://yourshop.com/account/orders/1001",
"imageUrl": "https://yourshop.com/images/parcel.png",
"audience": { "type": "all" },
"externalUserIds": ["1042"]
}curl -X POST https://api.superview.app/api/push/v1/notifications \
-H "Authorization: Bearer svp_your_key" \
-H "Content-Type: application/json" \
-d '{"title":"Your order has shipped","body":"Order #1001 is on its way.","audience":{"type":"all"},"externalUserIds":["1042"]}'Choose an audience and a time
Send { "type": "all" } for everyone subscribed. Filters all have to match. sendAt is an ISO 8601 time; a time in the past, or none, means now.
{
"title": "Pro members: new feature",
"body": "Reports are live in your dashboard.",
"audience": {
"type": "filters",
"filters": [
{ "field": "tag", "key": "plan", "op": "eq", "value": "pro" },
{ "field": "lastSession", "op": "withinDays", "days": 30 },
{ "field": "platform", "value": "android" }
]
},
"sendAt": "2026-11-02T09:00:00Z"
}{ "field": "tag", "key": "plan", "op": "eq", "value": "pro" }op is eq, neq, exists or notExists. exists and notExists take no value.{ "field": "externalUserId", "values": ["1042", "1043"] }Any of the IDs.{ "field": "email", "values": ["[email protected]"] }Any of the addresses, ignoring capital letters.{ "field": "loggedIn", "value": true }Whether the phone has a user ID set.{ "field": "lastSession", "op": "withinDays", "days": 30 }op is withinDays or olderThanDays.{ "field": "appVersion", "op": "lt", "value": "2.0" }op is eq, neq, lt or gt. Compared number by number: 1.10 is newer than 1.9.{ "field": "platform", "value": "ios" }ios or android.The answer
Counts fill in once sending finishes; read them later with GET.
{
"id": "6f1c2a4e-0d3b-4c1e-9a55-1f2e3d4c5b6a",
"title": "Your order has shipped",
"body": "Order #1001 is on its way.",
"launchUrl": "https://yourshop.com/account/orders/1001",
"imageUrl": "https://yourshop.com/images/parcel.png",
"audience": {
"type": "filters",
"filters": [{ "field": "externalUserId", "values": ["1042"] }]
},
"status": "sending",
"source": "api",
"sendAt": null,
"sentAt": null,
"targeted": 0,
"delivered": 0,
"failed": 0,
"opened": 0,
"createdAt": "2026-10-21T14:03:11Z"
}curl https://api.superview.app/api/push/v1/notifications/6f1c2a4e-0d3b-4c1e-9a55-1f2e3d4c5b6a \
-H "Authorization: Bearer svp_your_key"Cancel a scheduled notification
curl -X DELETE https://api.superview.app/api/push/v1/notifications/6f1c2a4e-0d3b-4c1e-9a55-1f2e3d4c5b6a \
-H "Authorization: Bearer svp_your_key"Rules
- Title up to 120 characters, message up to 1000. Links must start with
http://orhttps://. - Up to 60 requests a minute per key. Above that you get 429; wait a minute and try again.
- A wrong or revoked key gets 401. A rejected request gets 400 or 422 with a
reasonthat says what to fix.
Webhook connectors
A connector is a private URL. When your store sends a webhook to it, we fill in your title and message from the webhook and notify the phones of the customer it's about. A connector never sends to everyone; if no phone belongs to that customer, nothing is sent and the connector shows why.
For that, your website has to tell the app who is signed in (see Website). Templates use double braces with dot paths and numbers for lists, for example {{order.number}}, {{customer.first_name}}, {{line_items.0.title}}. A value that isn't in the webhook is left empty. There are no conditions and no HTML.
Shopify
- On your app's push dashboard, add a connector and choose Shopify. It fills in a title and message you can change, and finds the customer at
customer.idandemail. - In Shopify admin, open Settings → Notifications → Webhooks and choose Create webhook. Pick an event such as Order creation or Order fulfillment, format JSON, and paste the connector's URL.
- Copy the secret Shopify shows under the webhook list (“Your webhooks will be signed with …”) into the connector's signing secret, and save.
- Link signed-in customers to their phone: in Online Store → Themes → Edit code, open
theme.liquidand paste this just before</body>.
{% if customer %}
<script>
window.addEventListener('load', function () {
if (window.SuperView && SuperView.push) {
SuperView.push.setExternalUserId('{{ customer.id }}', '{{ customer.id | hmac_sha256: "your_identity_secret" }}');
SuperView.push.setEmail('{{ customer.email }}', '{{ customer.email | strip | downcase | hmac_sha256: "your_identity_secret" }}');
}
});
</script>
{% endif %}Replace your_identity_secret with the identity secret from Settings. Shopify's hmac_sha256 filter makes the hash while Shopify builds the page, so visitors only ever see the finished hash, never the secret. The secret does sit in your theme code, though, where anyone on your staff with theme access can read it. If that's a concern, leave identity verification off for Shopify or make the hashes in an app on your own server.
WordPress and WooCommerce
- On your app's push dashboard, add a connector and choose WooCommerce. It finds the customer at
customer_idandbilling.email. Copy its URL and signing secret. - In WordPress, open WooCommerce → Settings → Advanced → Webhooks and choose Add webhook. Set Status to Active, pick a topic such as Order updated, paste the URL into Delivery URL and the signing secret into Secret, and save.
- Link signed-in customers to their phone: add this to your theme's
functions.php(a child theme is safest) or a code snippets plugin. Put your identity secret inSUPERVIEW_IDENTITY_SECRET; better still, define it inwp-config.phpand remove that line here. PHP makes the hash on your server, so the secret never reaches the browser.
define('SUPERVIEW_IDENTITY_SECRET', 'your_identity_secret');
add_action('wp_footer', function () {
if (!is_user_logged_in()) {
return;
}
$user = wp_get_current_user();
$id = (string) get_current_user_id();
$email = strtolower(trim($user->user_email));
$idHash = hash_hmac('sha256', $id, SUPERVIEW_IDENTITY_SECRET);
$emailHash = hash_hmac('sha256', $email, SUPERVIEW_IDENTITY_SECRET);
?>
<script>
window.addEventListener('load', function () {
if (window.SuperView && SuperView.push) {
SuperView.push.setExternalUserId(<?php echo wp_json_encode($id); ?>, <?php echo wp_json_encode($idHash); ?>);
SuperView.push.setEmail(<?php echo wp_json_encode($email); ?>, <?php echo wp_json_encode($emailHash); ?>);
}
});
</script>
<?php
});There's no WordPress plugin; the snippet above is all it takes.
Anything else
Any system that can POST JSON to a URL works. Set where the user ID and email are in your JSON when you create the connector. Signing is optional: if you use the connector's secret, send the HMAC-SHA256 of the exact request body, hex encoded, in this header.
X-SuperView-Signature: sha256=<hex>const crypto = require('crypto');
const body = JSON.stringify({
order: { number: 'A-1001', status: 'shipped' },
customer: { id: '1042', email: '[email protected]' }
});
const signature = crypto
.createHmac('sha256', process.env.SUPERVIEW_CONNECTOR_SECRET)
.update(body)
.digest('hex');
await fetch(process.env.SUPERVIEW_CONNECTOR_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-SuperView-Signature': 'sha256=' + signature
},
body
});To try a connector without a real order, use Test with sample JSON on the dashboard. It shows the finished title and message and which customer would get it, and sends nothing.
Limits and boundaries
- It's your Firebase project. You can always send from the Firebase console without SuperView, and your app keeps receiving notifications whether or not you use this dashboard.
- iPhones only get notifications once your APNs key is uploaded in Firebase.
- “Delivered” means Firebase accepted the notification for that phone. Phones that are off or offline get it when they reconnect, and we can't see beyond that.
- Not included: saved audiences, A/B tests, translated versions and buttons on notifications.
Stuck?
Write to [email protected] with your order number. We reply within one business day.