Skip to content

Product alerts

Back-in-stock and price-drop alerts: the "Notify me" button, interest events and the broadcast to everyone interested.

A product alert is about a product, not one person: your server reports that a product is back in stock or cheaper, and relaybell sends it to everyone who showed interest in that product. It takes two parts.

1. Record interest from the browser. Call track() with the product's id while the visitor is subscribed — interest is only stored for a browser with a push subscription, so check isSubscribed() (or subscribe first):

JavaScript
// "Notify me when back in stock" on a sold-out product.
// For a variable product, send the selected VARIATION's id.
notifyButton.addEventListener("click", async () => {
  const r = await RelayBell.subscribeNow();               // must run from the click
  if (r.subscribed) RelayBell.track("waitlist.join", { productId: "1234" });
});

// Product page view (counts toward price-drop alerts)
RelayBell.isSubscribed().then((yes) => {
  if (yes) RelayBell.track("product.viewed", { productId: "1234" });
});

// Added to cart (counts toward price-drop alerts only for a subscribed browser)
RelayBell.track("cart.updated", { productId: "1234", product: "Blue Shoes", price: 49, url: location.href });

2. Report the product event from your server (API key). Send back_in_stock or price_drop to POST /api/v1/events with no externalId (and no subscriberId or endpoint) — an event that names a person is treated as that person's own event and is not broadcast. Only this authenticated route can broadcast; the browser's track() never does.

Shell
curl -X POST https://relaybell.com/api/v1/events \
  -H "Authorization: Bearer rb_live_xxxxx" -H "Content-Type: application/json" \
  -d '{ "event": "price_drop",
        "properties": { "productId": "1234-42", "parentId": "1234", "product": "Blue Shoes",
                        "url": "https://shop.example/p/blue-shoes", "oldPrice": 59, "newPrice": 49 } }'
PropertyDescription
productId *The product (or variation) that changed. Use the same id you send from the browser. Ids are up to 64 letters, digits and _ . : - — anything else is ignored.
parentIdFor a variation, its parent product — interest recorded on either id counts.
product, url, oldPrice, newPriceOptional details for your message, used as {product}, {url}, {oldPrice}, {newPrice} (any other property works as a placeholder too, e.g. {percentOff}).

Nothing is sent unless you have an enabled automation for that event (Automations → New automation → Back in stock / Price drop, or POST /api/v1/automations with "event": "back_in_stock" or "price_drop"). Its title, body and url are templates, e.g. "{product|This item} is back!". Who gets it:

  • back_in_stock — everyone on the product's waitlist (waitlist.join for productId or parentId). The waitlist is consumed: each person is taken off it as the alert goes out, so they get one alert per join and a later restock doesn't alert them again. It is sent as a transactional message, so the daily frequency cap can't drop an alert someone asked for.
  • price_drop — anyone on the waitlist, plus subscribers who viewed (product.viewed) or carted (cart.updated) the product in the last 30 days. This list is not consumed. Price drops are deduplicated: at most one price_drop alert per product (keyed by parentId, else productId) every 10 minutes — repeats inside that window send nothing.

For product alerts, cancelOn and oncePerSubscriber don't apply; conditions (checked against the event's properties), delaySeconds and your quiet hours still do. Unsubscribed people are never included, and one alert reaches at most 100,000 people. The 202 answer adds productAlerts (alerts created) and alertAudience (people reached).