skills/marketing-growth/push-notifications/SKILL.md
Send browser push notifications for price drops, back-in-stock alerts, and cart reminders to bring shoppers back without needing their email
npx skillsauth add finsilabs/awesome-ecommerce-skills push-notificationsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Web push notifications deliver timely messages to subscribers even when they are not on your site — for back-in-stock alerts, price drops, and cart reminders. Push requires explicit browser permission, making the opt-in prompt timing critical. For Shopify, WooCommerce, and BigCommerce, dedicated push notification apps (PushOwl, OneSignal) handle all the subscriber management, triggering logic, and delivery without custom service worker code.
| Platform | Best For | Shopify | WooCommerce | BigCommerce | Price | |----------|---------|---------|-------------|-------------|-------| | PushOwl | Shopify-native, back-in-stock + abandonment | App Store | — | — | Free tier; $19+/mo | | OneSignal | All platforms, free tier, highly configurable | Via JS tag | Plugin | Via JS tag | Free tier; $9+/mo | | Klaviyo Web Push | Already using Klaviyo for email | App Store | Plugin | App Marketplace | Included in Klaviyo | | PushEngage | WooCommerce + segmented campaigns | — | Plugin | Via JS tag | Free tier; $9+/mo |
Shopify recommendation: Use PushOwl — it's the most integrated Shopify push app with built-in back-in-stock, cart abandonment, and shipping alerts.
WooCommerce recommendation: Use PushEngage or OneSignal — both have WordPress plugins and handle subscriber management automatically.
<script src="https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js" defer></script>
<script>
window.OneSignalDeferred = window.OneSignalDeferred || [];
OneSignalDeferred.push(async function(OneSignal) {
await OneSignal.init({ appId: "YOUR_APP_ID" });
});
</script>
For headless stores, implement push using the Web Push API directly:
// Service worker — save as /sw.js in your public directory
self.addEventListener('push', (event) => {
const data = event.data?.json() ?? {};
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: data.icon ?? '/icons/icon-192.png',
image: data.image,
data: { url: data.url },
actions: data.actions ?? [],
})
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
event.waitUntil(clients.openWindow(event.notification.data?.url ?? '/'));
});
// Server-side push sending using the web-push library
import webpush from 'web-push';
webpush.setVapidDetails(
'mailto:[email protected]',
process.env.VAPID_PUBLIC_KEY!,
process.env.VAPID_PRIVATE_KEY!
);
// Generate VAPID keys once: npx web-push generate-vapid-keys
async function sendPushNotification(subscription: PushSubscription, payload: {
title: string;
body: string;
url: string;
icon?: string;
}) {
try {
await webpush.sendNotification(subscription, JSON.stringify(payload));
} catch (err: any) {
if (err.statusCode === 410) {
// Subscription expired — remove from database
await db.pushSubscriptions.deleteByEndpoint(subscription.endpoint);
}
}
}
// Triggered when inventory transitions from 0 to > 0
async function notifyBackInStock(productId: string) {
const product = await db.products.findById(productId);
const waitlist = await db.pushWaitlist.findByProduct(productId);
for (const entry of waitlist) {
const sub = await db.pushSubscriptions.findByUserId(entry.userId);
if (!sub) continue;
await sendPushNotification(sub, {
title: 'Back in stock!',
body: `${product.name} is available again`,
url: `${process.env.STORE_URL}/products/${product.slug}`,
icon: product.images[0]?.url,
});
}
}
The most critical factor for push notification effectiveness is when you show the permission prompt. Never ask on the first page load.
Best triggers for the opt-in prompt:
In PushOwl: go to Settings → Opt-in Prompt → Advanced and set the trigger condition. In PushEngage: go to Subscription Prompt → Display Rules and set page view count or cart event triggers.
Priority order by conversion rate:
In PushOwl: all four are available as pre-built automations under Automations — enable them and customize the message.
| Metric | Healthy Target | Where to Find | |--------|----------------|---------------| | Opt-in rate | 5–15% of new visitors | App dashboard | | Back-in-stock click rate | 15–25% | PushOwl/PushEngage analytics | | Cart abandonment recovery rate | 2–5% | App analytics | | Unsubscribe rate per campaign | < 2% | App analytics |
If unsubscribe rate is above 2%, reduce push frequency or improve message relevance.
| Problem | Solution |
|---------|----------|
| Low opt-in rate | Move the permission prompt to after add-to-cart or product view #3; never show on first load |
| iOS users not receiving push | Web push on iOS requires iOS 16.4+ and the user must install the site as a PWA (Add to Home Screen); this is a browser limitation |
| Push notifications not firing for back-in-stock | Verify the inventory webhook is connected in PushOwl/PushEngage settings; check the app's automation logs |
| High unsubscribe rate | Reduce push frequency; add preference management so subscribers can choose which notification types they receive |
| Duplicate subscriptions in the database | For custom implementations, use upsert keyed on (userId, endpoint) |
tools
Let shoppers save products to a wishlist, share it with friends, and get notified when saved items come back in stock or drop in price
development
Build a themeable storefront with design tokens and CSS custom properties that supports white-labeling, multi-brand variants, and dark mode
development
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results powered by Algolia or Elasticsearch
development
Build a mobile-first storefront with thumb-friendly navigation, sticky add-to-cart buttons, and touch-optimized components for high mobile conversion