OneSignal: Custom Newsletter Forms
Connect a custom Shopify newsletter form to OneSignal through Vendo and verify the subscriber identity flow.
Last reviewed September 15, 2026
If you built your own newsletter capture, Vendo can send that email to OneSignal as a real Email subscription. You do not need to write any OneSignal code. Your capture can be a popup, an inline banner, a footer signup or any other form that is not a stock Shopify form.
This article covers the two integration paths, what Vendo does automatically, where the email lands in OneSignal and how to test the flow end-to-end.
Prerequisites
Before any of this works, three things must be true on the storefront:
- The Vendo Shopify app is installed and the OneSignal destination is configured (App ID entered in Vendo > Destinations > OneSignal).
- The Vendo theme app embed is enabled in the active theme: Online Store > Themes > Customize > App embeds > Vendo: ON. This embed loads the OneSignal Web SDK and Vendo’s newsletter listener.
- A Customer Identification value (
user_id_type) is set on the OneSignal Events tab, usually Shopify Customer ID. It controls which ID Vendo uses for logged-in customers in OneSignal.
Without (2) in particular, your form still submits to your own backend, but nothing reaches OneSignal.
Path A — Auto-detection (recommended)
This is the simplest integration. You write a standard HTML form with two specific traits, and Vendo’s theme listener does the rest.
The contract
Vendo’s storefront listener scans the page for forms that match any of these selectors:
form[action^="/contact#"]
form.newsletter-form
form.klaviyo-form
form[id*="newsletter" i]
form[class*="newsletter"]For each matched form, Vendo adds a submit event listener that reads the value from input[type="email"] inside the form. So your form must:
- Be a real
<form>element (not a<div>with an input). - Have an
idorclasswhose name containsnewsletter(or match one of the other selectors above). - Contain an
<input type="email">.
That is all. Your submit handler can call event.preventDefault() and post the email to your own backend with fetch(). Vendo’s listener runs on the submit event itself, so preventDefault() does not stop it.
What Vendo does when it detects a submission
- Captures the email and writes a record into
localStorage.vendo_identitywith_pending_event = 'newsletter_registered'. - Calls
OneSignal.login(email)on the SDK that the Vendo theme embed loaded. The email becomes the OneSignal External ID. - Calls
OneSignal.User.addTags({ email }). This sets theemailtag on the current OneSignal user. - Calls
OneSignal.User.addEmail(email). This creates a real Email subscription channel on that user, withenabled: true. The user can then receive email. - Polls
/apps/vendo/customer-lookup?email=...(the Vendo app proxy) att=0, 2s, 6s, 14s. It does this on submit for bothuser_id_typevalues. - When Shopify returns a customer ID, Vendo saves it in
vendo_identity. The OneSignal External ID stays the email. - If the customer does not exist yet (typical for first-time signups), Vendo saves
_vendo_pending_lookupin localStorage. It retries on each later page load (up to 5 cross-page attempts). - On the next Vendo pixel event after submission, sends a
Newsletter Registeredevent with the email to every connected destination (OneSignal custom event, Mixpanel, Segment, Customer.io and others).
Minimal example
A working inline newsletter banner that satisfies the contract:
<form class="newsletter-form" id="my-newsletter">
<input type="email" name="email" placeholder="you@example.com" required />
<button type="submit">Subscribe</button>
</form>
<script>
document
.getElementById('my-newsletter')
.addEventListener('submit', function (e) {
e.preventDefault();
var email = e.target.querySelector('input[type="email"]').value.trim();
if (!email) return;
// Post to your own backend. Vendo's listener also captures the email on this submit.
fetch('/your/backend/endpoint', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email }),
});
});
</script>That is it. Your code does not need a OneSignal App ID, because Vendo provides it from the Vendo app metafield. Your code does not need to load the OneSignal SDK, because Vendo loads it. Your code does not need identify calls, because Vendo handles identity, including the deferred customer-ID lookup.
What lands in OneSignal
A single user record has the new data. It is the existing push subscriber’s record if the visitor allowed push before, or a new user if not. The record has:
- An Email subscription channel with
token = <email>andenabled = true - A tag
email = <email> external_id = <email>
The email subscription is attached to the existing user record. It does not create a separate “email-only” user. This is intentional. It keeps push, email and future purchases merged on one user record.
Path B — Manual identification
Use Path B when:
- Your popup is not a
<form>(it is a<div>with inputs) - You cannot add
newsletterto the class or id (theming constraints) - You want to capture the email at a different point than form submit (for example, on the “next” button of a multi-step modal)
Path B writes the same Vendo data structure that Path A writes, but from your own code instead of through auto-detection.
What to write
function vendoCaptureNewsletter(email) {
var data = JSON.parse(localStorage.getItem('vendo_identity') || '{}');
data.email = email;
delete data.shopify_customer_id;
data.newsletter_subscribed = true;
data.newsletter_subscribed_at = new Date().toISOString();
data._pending_event = 'newsletter_registered';
localStorage.setItem('vendo_identity', JSON.stringify(data));
// Triggers the redirect-page customer-ID lookup on the next page load
localStorage.setItem('_vendo_nl_email', email);
}This function alone sends Newsletter Registered to all destinations on the next pixel event. Vendo attaches the Email subscription to the OneSignal user only on the next page load. To attach it on the same page, also add this function:
function vendoAttachOneSignalEmail(email) {
window.OneSignalDeferred = window.OneSignalDeferred || [];
window.OneSignalDeferred.push(async function (OneSignal) {
try {
// Log in before addEmail(), in the same order as Vendo's theme code,
// so the email becomes the External ID on one OneSignal user.
await OneSignal.login(email);
OneSignal.User.addTags({ email: email });
await OneSignal.User.addEmail(email);
} catch (e) {
/* push permission may be blocked — addEmail still works */
}
});
}Then call both functions from your custom UI:
yourCustomPopup.onSubmit(function (email) {
vendoCaptureNewsletter(email);
vendoAttachOneSignalEmail(email);
// ...your own backend POST here
});OneSignal.User.addEmail() is idempotent. Your code and Vendo’s auto-detection can both run on the same submit with no harm.
What Vendo does not do
| Concern | Owner |
|---|---|
| GDPR / CAN-SPAM consent capture, storage, audit trail | You — Vendo does not set any consent_status or opt-in timestamp |
| Backend email storage (for re-engagement and exports) | You — the fetch() to your own endpoint is yours alone |
| Email validation / disposable-domain filtering | You (or your backend) |
| Double opt-in confirmation emails | You / OneSignal Journeys |
| Unsubscribe link / preferences page | You / OneSignal |
For consent in particular, we recommend that you set your own tags from the same submit handler:
OneSignal.User.addTags({
marketing_consent: 'granted',
marketing_consent_at: new Date().toISOString(),
marketing_consent_source: 'site_newsletter_popup_v1',
});These tags stay with the email subscription. They give you an auditable property to filter on in OneSignal segments.
Where to find the user in the OneSignal dashboard
After a test submission:
- Open the dashboard at
https://dashboard.onesignal.com/apps/<your-app-id>/users. Make sure the App ID matches the one configured in Vendo. Newsletter signups go to the app configured in Vendo, so it is easy to look at the wrong app. - In the User Records page, change the search filter dropdown from External ID to Email.
- Search for the test email. The user appears with an Email channel and an
emailtag that matches the test value. - If the visitor was already a push subscriber on this browser, the email subscription goes on that same user record. The Users count does not increase. The user gets another subscription channel.
- Check
external_id. Vendo sets it to the test email before it adds the Email subscription. The customer lookup does not change it.
Why your tests sometimes look like “no user was created”
The most common causes, in order of frequency:
- Wrong app. The same OneSignal account has multiple OneSignal apps, and you are looking at the wrong one. Confirm that the App ID in the dashboard URL matches
OneSignal.config.appIdin the storefront’s DevTools console. - Dashboard indexing delay. The REST API accepts the subscription within milliseconds (HTTP 201). But the dashboard Users view can take a couple of minutes to show a new subscription.
Testing the flow
- Open the storefront in an incognito window and add
?vendo_debug=1to the URL. See Debug Mode for what to expect in the console. - Open DevTools > Network and filter to
onesignal.com. - Submit your custom form with a fresh test email.
- Look for these entries, in order:
- Console:
[Vendo] Newsletter email captured: <email> - Console:
[Vendo] Newsletter: resolving customer ID... - Console:
[Vendo] Newsletter: OneSignal identified as <email> — email subscription added - Network:
PATCH https://api.onesignal.com/apps/<app_id>/users/by/onesignal_id/<onesignal_id>returning 202 (setsemailtag) - Network:
POST https://api.onesignal.com/apps/<app_id>/users/by/onesignal_id/<onesignal_id>/subscriptionsreturning 201 (creates Email subscription, response body contains the new subscription’s id)
- Console:
- Open the OneSignal dashboard at
https://dashboard.onesignal.com/apps/<app_id>/users. Set the filter to Email and search for the test email. The user is there with an Email channel.
To confirm the App ID that Vendo actually sends to (compared to what the Vendo admin shows), run this in the storefront’s DevTools console:
OneSignal.config.appId;This returns the App ID that the SDK initialized with on this page. That is the live destination of any newsletter submission.
Troubleshooting
My form submits but I see no [Vendo] Newsletter email captured log
- The Vendo theme app embed is off. Enable it again: Online Store > Themes > Customize > App embeds > Vendo: ON > Save.
The log appears but no OneSignal API requests fire in the Network tab
- The OneSignal SDK did not load. Check that the OneSignal destination is saved in the Vendo admin (App ID entered and saved). Reload the storefront.
- Push permission is blocked at the browser level. That is fine for push, but
addEmail()should still run. Check the storefront DevTools console for OneSignal errors.
The user appears in OneSignal but with external_id = <some UUID I don't recognize>
- An earlier manual
OneSignal.login(...)call on this browser set that UUID. Vendo does not set arbitrary UUIDs asexternal_id. To reset for a clean test, runOneSignal.logout()in the storefront’s DevTools console and reload.
The customer-lookup never resolves
- The submitted email has no matching Shopify customer record yet. Complete checkout with the same email, or create the customer manually in Shopify admin (Customers > Add customer). Then refresh the storefront. The deferred path picks it up within a couple of page loads.
Related
- OneSignal destination setup: full OneSignal destination setup, events, tags and payloads
- Debug Mode: how to inspect every event Vendo sends from the storefront
- Sending Custom Events: sending arbitrary events through Shopify’s Web Pixel API
Support
If your custom form does not work as expected, turn on Debug Mode and reproduce the issue. Then email the console output and a screenshot of the OneSignal Users page (with the Email filter applied) to support@vendodata.com.