If you landed here, you probably want to use PushOwl on your store's custom frontend. First, let us clarify what a custom frontend is. If your store website is not built on top of a Shopify store theme, then you are on a custom frontend. Eg. maybe it is built using React or made on Webflow, or on Nacelle platform i.e. you are not using the visual website interface that you got when you created your Shopify store.

Note: If you specifically using the Nacelle platform for your store frontend, please refer to our integration with Nacelle article. Otherwise, read on.

Requirements to use PushOwl

We offer a PushOwl SDK that can be used on any website as long as you can fulfill the following requirements:

  1. You should at least be using Shopify's backend. i.e. your inventory etc data should be on Shopify.
  2. You should have the PushOwl app installed on your store.
  3. Be able to put a JavaScript snippet on the website pages.

Note: Not all features in PushOwl are supported at the moment on the custom frontend through our SDK. But we are actively working on supporting them all.

Steps to integrate PushOwl

STEP 1: Inject PushOwl snippet

Inject the following JavaScript code snippet in the website such that it gets executed on every page. In the case of a single-page app, it can just be executed once when the app initializes.

window.pushowl = window.pushowl || {
queue: [],
trigger: function (taskName, taskData) {
return new Promise((resolve, reject) => {
promise: { resolve, reject }
init: function () {
const subdomain = '<SHOPIFY_SUBDOMAIN_HERE>'
if (!subdomain) {
this.subdomain = subdomain
var s = document.createElement('script')
s.type = 'text/javascript'
s.async = true
s.src =
'https://cdn.pushowl.com/sdks/pushowl-sdk.js?subdomain=' +
subdomain +
'&environment=production&shop=' +
subdomain +
var x = document.getElementsByTagName('script')[0]
x.parentNode.insertBefore(s, x)

Note: you need to replace <SHOPIFY_SUBDOMAIN_HERE> with your actual Shopify subdomain.

STEP 2: Host the Service worker file (Optional, but recommended)

Next, you need to host the following file on your website - https://cdn.pushowl.com/sdks/service-worker.js

and it should be available on your website at the following URL - https://your-store.com/pushowl/service-worker.js

Note: Substitute your-store.com with your actual domain

If hosting the file on your domain is not possible, PushOwl will still work but with a slightly different behavior. Because of technical limitations here, instead of showing a native browser on your website, PushOwl will open a popup with the native browser prompt inside it. This popup basically opens <your_subdomain.powl.co URL and hence, the visitor actually would subscribe to a subdomain of powl.co and would see the same URL in the actual notification that goes to them.

STEP 3: Trigger the permission prompt

At any point, when you want to trigger the permission prompt, you can execute either of the following code snippets depending on whether you want a browser prompt or a custom prompt.

Browser prompt:

window.pushowl.trigger("getCurrentPermission").then((permission) => {
if (permission !== "default") return;
window.pushowl.trigger("showWidget", { type: "browserPrompt", });

Custom prompt:

window.pushowl.trigger("getCurrentPermission").then((permission) => {
if (permission !== "default") return;
window.pushowl.trigger("showWidget", {
type: "customPrompt",
title: "Lets get you offers!",
description: "Subscribe to get amazing offers",
yesButton: { label: "Subscribe" },
noButton: { label: "Later" },
logo: "image url here",
position: { default: "top-left", mobile: "bottom" },
overlay: { enabled: false }

Whenever this script executes, the prompt will show up and your website visitors can subscribe to your store. That means you are not ready to send them campaigns to notify them about sales, discount coupons, etc.

IMPORTANT: If you were not able to host the service worker file mentioned in Step 2, you should go the custom prompt way. Otherwise, a popup showing a native browser prompt would show up out of nowhere and the user would have no context. So it is better to show a custom prompt first to set context which would then show the popup to get actual permission. For more details, read Step 2.

STEP 4: Abandoned Cart Recovery

To make Abandoned Cart Recovery automation work on your store, you need to first be able to detect when the cart updates. When you can do so, upon every cart update you need to trigger another API to sync your cart to the PushOwl backend, like so:

const cart = {
checkoutToken|token: <replace_with_token>,
items: [
{ variantId: 2323, productId: 34343, quantity: 3 },
{ variantId: 23, productId: 1943, quantity: 1},
window.pushowl.trigger('syncCart', cart)

As you'll notice in the code above, the cart object needs to be in the specified structure:

  1. You should pass either token (cart token) or checkoutToken (checkout token) - whatever you can get.
  2. A list of items with each item as an object having productId, variantId and quantity. Note that the productId and variantId need to be the numeric IDs (3483274) and not the guid (guid://shopify/product/34234).

STEP 5: Syncing the checkout token (OPTIONAL)

This is an optional step. In many stores, we don't get any token during cart updates. It is only at the time of actual checkout that we get a checkout token. If your store behaves that way, then while syncing the cart in the above step, you can skip the token in the cart object. And when you actually get the checkout token, you can sync it to the PushOwl backend like so:

window.pushowl.trigger('setCheckoutId', checkoutId)

And there you have your Abandoned Cart Recovery automation working!

STEP 6: Syncing the customer ID

Whenever during the lifecycle of a user's session you get hold of the customer ID (from Shopify), you can sync it once to PushOwl like so:

window.pushowl.trigger('setCustomerId', customerId)

Other Automations

Supporting other automations (like Browse abandonment, Price drop etc) in the SDK is still being worked on and we'll update the documentation here as and when they are available.

Did this answer your question?