Skip to main content

Installing the Onsite Messaging script

Prerequisites

  • For GTM Implementation: Google Tag Manager correctly installed on your website. (GTM Installation Guide)

  • Access to your GTM container with publish permissions

  • Access to your website’s dataLayer or variables for:

    • Order totals and revenue

    • Customer email addresses

    • Currency codes

    • Discount/coupon codes

  • A test environment to validate implementation

  • (Optional) Voyado Chrome Extension installed for testing

Implementation paths

Google Tag Manager (SPA)

Single Page Applications (SPAs) require special handling because page navigation doesn’t trigger traditional page loads. This guide shows how to implement all four recommended tags.

Understanding SPA Requirements

Why SPAs are different:

Critical Rule: If your trigger uses custom pageload events, your exceptions must also use custom pageload events. Mixing event types (e.g., history change with pageview exceptions) will cause failures.

  • Navigation happens without full page reloads

  • Scripts must trigger on virtual page views

  • Open widgets persist during navigation and must be explicitly closed

  • All triggers must use consistent event types

GTM Tag Configuration

You’ll create four tags. Suggested naming:

  1. Voyado Onsite Cornerwidget – Displays messaging widgets broadly on the website

  2. Voyado Onsite Hide – Closes any open widgets on checkout/cart pages

  3. Voyado Onsite Purchase – Tracks conversions and displays messages on order confirmation page

  4. Voyado Onsite Login – Identifies user and enables personalized onsite messaging

Tag #1: Voyado Onsite Cornerwidget

Purpose: Load and display messaging widgets on landing pages and virtual page views

Trigger: All pageviews EXCEPT checkout, cart, and order confirmation pages. Should also be excluded when login script is called instead.

Script:

<script>
if (typeof redeal !== 'function') {
  (function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');
}
redeal('cornerwidget');
</script>

Why the if (typeof redeal !== 'function') check? This prevents loading the script multiple times on SPAs. The script loader only runs once, but redeal('cornerwidget') can be called on each virtual page load.

Configuration in GTM:

  • Tag Type: Custom HTML

  • Trigger: Custom Event on page load

  • Exceptions: Checkout page, Cart page, Order confirmation page and Login event

Alternative tag names: Replace ‘cornerwidget’ with any tag name configured in Onsite Manager. Use multiple tags with different conditions to trigger different onsite messages.

Tag #2: Voyado Onsite Hide

Purpose: Close open widgets when users navigate to pages where widgets shouldn’t appear (checkout, cart)

Why is this needed? On SPAs, excluding pages from Tag #1 only prevents NEW widgets from loading. It doesn’t close widgets that are already open. This tag explicitly closes them.

Trigger: Pageview on checkout and cart pages

Script:

<script>
if(typeof redealHide === 'function') {
  redealHide();
}
</script>

Configuration in GTM:

  • Tag Type: Custom HTML

  • Trigger: Custom Event on page load when Page Path contains “/checkout” or “/cart”

Tag #3: Voyado Onsite Purchase

Purpose: Track conversions and optionally trigger post‑purchase onsite messages

Trigger: Order confirmation page load (immediately after purchase)

Script:

<script>
if (typeof redeal !== 'function') {
  (function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');
}
if(typeof IsRedealOpen !== 'function' || !IsRedealOpen('checkout')) {
  redeal('checkout', {
    total: {{sumtotal}},
    revenue: {{sumrevenue}},
    currency: {{currencycode}},
    email: {{userEmail}},
    coupons: [{{discountcode}}]
  });
}
</script>

Variable Name

Type

Example value

Description

{{sumtotal}}

Data Layer Variable

"113.75"

Total amount paid by customer (string)

{{sumrevenue}}

Data Layer Variable

"93"

Revenue excluding tax and shipping (string)

{{currencycode}}

Data Layer Variable

"SEK"

ISO currency code

{{userEmail}}

Data Layer Variable

"john@doe.com"

Customer email address

{{discountcode}}

Data Layer Variable

"aJ7q54JU"

Coupon/discount code used (can be array)

Expected output format:

redeal('checkout', {
  total: "113.75",
  revenue: "93",
  currency: "SEK",
  email: "john@doe.com",
  coupons: ["aJ7q54JU"]
});

Important notes:

  • total = full amount paid by customer (including tax, shipping, fees)

  • revenue = amount excluding tax, shipping, and fees

  • coupons should be an array, even with one code

  • Missing or null values won’t break functionality but will limit tracking and reporting

  • Optional fields: name, phone (useful for prefilling onsite messages and automatically identifying visitors)

Configuration in GTM:

Tag Type: Custom HTML

Trigger: Custom Event associated with reaching the order confirmation page, for example “purchase”, or when Page Path contains “/order‑confirmation” or “/thank‑you”

Tag #4: Voyado Onsite Login

Purpose: Identifying unidentified visitors and triggering personalized onsite messages

When to trigger:

  • When a user actively logs in (login button click)

  • On page load if user is already logged in (“soft login”)

Trigger: Login event OR pageview when user is authenticated

Important: The login script should only be called once per session, not on subsequent page views after the login event occurs. On subsequent page views calling the cornerwidget script is expected.

Script:

<script>
if (typeof redeal !== 'function') {
  (function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');
}
if(typeof IsRedealOpen !== 'function' || !IsRedealOpen('login')) {
  redeal('login', {
    email: {{userEmail}}
  });
}
</script>

Required GTM Variables:

  • {{userEmail}} – User’s email address (unhashed string)

Optional fields:

  • phone: {{userPhone}} – User’s phone number

  • contactId: {{contactID}} – User’s contact ID in Voyado Engage

Configuration in GTM:

  • Tag Type: Custom HTML

  • Trigger: Custom Event user_login OR first page view when User State = “logged_in”, expected to fire only once per session

Benefits:

  • Enables automated consent updates via Reach Ability feature

  • Triggers onsite messages to complete missing profile data

  • Improves contact data quality

  • Improves onsite scripts user identification

Google Tag Manager (Traditional Sites)

For traditional multi‑page applications (non‑SPAs), the implementation is simpler because each page navigation is a full page load.

Key Differences from SPA Implementation

  • No need for the if (typeof redeal !== 'function') check

  • No need for the Hide tag (widgets don’t persist across page loads)

Tag #1: Cornerwidget (Traditional Sites)

Script:

<script>
(function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');

redeal('cornerwidget');
</script>

Trigger: All Pages EXCEPT checkout and order confirmation.

Tag #2: Purchase (Traditional Sites)

Script:

<script>
(function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');

redeal('checkout', {
  total: {{sumtotal}},
  revenue: {{sumrevenue}},
  currency: {{currencycode}},
  email: {{userEmail}},
  coupons: [{{discountcode}}]
});
</script>

Trigger: Order Confirmation Page

Tag #3: Login (Traditional Sites)

Script:

<script>
(function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');

redeal('login', {
  email: {{userEmail}}
});
</script>

Trigger: Login success event OR first page view when user is authenticated

Direct implementation

For sites without GTM or when you want full control, you can add the script directly to your HTML.

Basic script structure

Place this immediately after the opening &lt;body&gt; tag on all pages where messaging should appear:

<script>
(function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');
</script>

This loads the script asynchronously without blocking page rendering.

Implementing each tag type

Cornerwidget (landing pages):

<script>
(function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');

redeal('cornerwidget');
</script>

With user prefill (when user data is available):

<script>
(function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');

redeal('cornerwidget', {
  email: "",
  name: "",
  phone: ""
});
</script>

Checkout (order confirmation page):

<script>
(function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');

redeal('checkout', {
  total: "",
  revenue: "",
  currency: "",
  email: "",
  coupons: []
});
</script>

Login (login page or when user is authenticated):

<script>
(function(i,s,o,g,r,a,m){i['RedealObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window, document, 'script', 'https://static.redeal.se/widget/js/redeal.js', 'redeal');

redeal('login', {
  email: "",
  phone: ""
});
</script>

Hide function (SPAs only):

// Call this when navigating to pages where widgets should be hidden
if(typeof redealHide === 'function') {
  redealHide();
}

Script reference

Standard tag names

Tag name

When to use

Recommended data

cornerwidget

Landing pages, general browsing

None (optional/if available: email, name, phone, contact ID)

checkout

Order confirmation/thank you page

total, revenue, currency, email, coupons

login

After user login or when authenticated

email (optional/alternative: phone, contact ID)

custom

Any custom trigger defined in Onsite Manager

Varies by onsite message

Data field specifications

Checkout fields:

{
  total: "113.75",        // String: Total amount paid (including tax, shipping)
  revenue: "93",          // String: Revenue excluding tax and fees
  currency: "SEK",        // String: ISO 4217 currency code
  email: "user@example.com",  // String: Customer email
  coupons: ["CODE123"],   // Array: Discount codes used
  name: "John Doe",       // Optional String: Customer name
  phone: "+46701234567",  // Optional String: Customer phone
  contactId: "b9a02dc6-52b8-4e11-b929-b37500f002f1"  // Optional String: User’s Contact ID in Engage
}

Cornerwidget fields (all optional):

{
  email: "user@example.com",
  name: "John Doe",
  phone: "+46701234567",
  contactId: "b9a02dc6-52b8-4e11-b929-b37500f002f1"
}

Login fields

{
  email: "user@example.com",     // Optional: User email
  phone: "+46701234567",         // Optional: User phone
  contactId: "b9a02dc6-52b8-4e11-b929-b37500f002f1"  // Optional: User’s Contact ID in Engage
}

Note

Which of the field(s) above to pass in the script call is optional, but at least one needs to be passed for script identification upon login to work.

Custom trigger tags

You can define custom tags in Onsite Manager and trigger them:

redeal('custom-tag-name');

Use case: Trigger different onsite messages based on user actions:

<button onclick="redeal('special-offer)">View Offer</button>

A/B Testing: If multiple onsite messages use the same script tag and fulfil any additional targeting criteria needed to be displayed, one will be randomly selected and displayed to the user.

Hide function

Basic usage (hide all open widgets):

redealHide();

Onsite message URL links

Each onsite message in Onsite Manager generates an onsite message URL link as well as a QR code. Use these links in emails or social media to drive traffic to your web­site and trigger the appropriate onsite messages automatically.

With personalization variables (for email marketing):

https://yoursite.com/onsite-message-url?email=*|EMAIL|*&name=*|NAME|*

Replace *|EMAIL|* and *|NAME|* with the merge tag format from your email service provider.

Domain matching

Important: Onsite messages only trigger on domains configured in Onsite Manager.

Use:

Production domain: www.example.com

Test subdomain: test.example.com

Do not use:

Local development: localhost or 127.0.0.1

IP addresses: 192.168.1.100

For testing on non-production domains: Add the test domain to your site configuration in Onsite Manager.

Testing and validation

Using the Chrome Extension

  1. Install the Voyado Chrome Extension

  2. Navigate to your website

  3. Wait for the page to fully load

  4. Click the Voyado extension icon

  5. Verify that the script is detected

Note

The extension only detects if the script is loaded on the current page. It doesn’t validate triggers or data.

Browser Console Checks

Use this URL parameter to activate debug mode:

https://yoursite.com/?voyado-debug

Open your browser’s developer console (F12) and verify:

  • Script loaded successfully: typeof redeal === 'function' — Should return: true

  • Check if widget is open: typeof IsRedealOpen === 'function' && IsRedealOpen('cornerwidget') — Should return: true if cornerwidget is open

  • View script errors: Look for red errors in the console. Common issues:

    • Failed to load resource: https://static.redeal.se/widget/js/redeal.js – Script blocked by firewall/CSP

    • redeal is not a function – Script not loaded or loaded after trigger call

Clear testing session

Use this URL parameter to reset your test session:

https://yoursite.com/?voyado-clear

This clears local and session storage, allowing you to test onsite messages as an unidentified/new visitor.

Testing checklist

  • Script loads on all intended pages

  • Only one script call loads per pageview

  • Cornerwidget appears on landing pages

  • Cornerwidget does NOT appear on checkout/cart pages

  • Open widgets close when navigating to checkout (SPAs only)

  • Checkout tag fires on order confirmation with correct data

  • Login tag fires when user logs in

  • Console shows no JavaScript errors

  • All GTM variables return expected values

  • Onsite message URL links work and trigger onsite messages

  • Onsite messages only trigger on configured domains

  • Test with ?voyado-clear to simulate new visitors

Note

For implementations using Google Tag Manager, using GTM’s Preview mode to ensure the tags are correctly installed and that triggers are firing appropriately with complete and correctly formatted variables is highly recommended.

Network tab verification

In browser DevTools > Network tab:

  1. Filter by “redeal”

  2. Verify redeal.js loads successfully (Status: 200)

  3. Check that POST requests to Voyado API return 200 status

  4. Verify request payloads contain expected data

Troubleshooting

Script not loading

Symptoms:

  • Chrome extension shows no detection

  • typeof redeal returns undefined

  • No network requests to static.redeal.se

Possible causes:

1. Content Security Policy (CSP) blocking the script

Solution: Add https://static.redeal.se to your CSP script‑src directive

2. Ad blocker or privacy extension

Solution: Disable extensions for testing or whitelist your domain

3. Firewall blocking external scripts

Solution: Whitelist static.redeal.se in your firewall rules

4. Incorrect GTM trigger configuration

Solution: Check trigger fires on page load using GTM Preview mode

5. Script tag syntax error

Solution: Validate HTML, ensure no extra characters in script tag

Widget not appearing

Symptoms:

  • Script loads but no widget visible

  • Console shows no errors

Possible causes:

1. Domain not configured in Onsite Manager

Solution: Verify your domain is added to the onsite message configuration

2. Onsite message not active

Solution: Check onsite message status in Onsite Manager

3. Onsite message already shown to this user

Solution: Test with ?voyado‑clear URL parameter

4. Wrong tag name

Solution: Verify tag name in code matches Onsite Manager configuration

5. Z‑index conflict

Solution: Check if widget is rendering but hidden behind other elements

Conversion not tracking

Symptoms:

  • Checkout tag fires but conversions don’t appear in reports

Possible causes:

1. Variables returning null or undefined

Solution: Use GTM Preview to verify variable values

2. Incorrect data types

Solution: Ensure total, revenue are strings, coupons is array

3. Currency code format

Solution: Use ISO 4217 codes (SEK, USD, EUR, etc.)

4. Race condition (script triggers before GTM variables populate)

Solution: Add a small delay or ensure dataLayer pushes before tag fires

GTM variables not populating

Symptoms:

  • GTM Preview shows undefined or null variable values

Solutions:

  1. Verify dataLayer structure matches your variable configuration

  2. Check that dataLayer.push() happens before page load events

  3. Use “Data Layer Variable” type (not “JavaScript Variable”) in GTM

  4. Test dataLayer in console: console.log(dataLayer)

SPA issues

Widget persists on checkout page:

  • Ensure Hide tag is implemented and triggering correctly

  • Verify Hide tag trigger uses same event type as other triggers

  • Check GTM Preview to confirm Hide tag fires

Widget not appearing after navigation:

  • Confirm Cornerwidget tag triggers on virtual pageviews

  • Verify history change events are captured in GTM

  • Check that custom events fire consistently

Script loaded multiple times:

  • Ensure if (typeof redeal !== 'function') wrapper is present

  • Check GTM Preview for duplicate tag fires

Console error messages

Common errors and solutions:

Error

Cause

Solution

Failed to load resource: https://static.redeal.se/…

Script blocked

Check CSP, firewall, ad blockers

redeal is not a function

Script not loaded before call

Ensure script loader runs first

IsRedealOpen is not defined

Script not fully initialized

Add conditional check: typeof IsRedealOpen === 'function'

Cannot read property 'email' of undefined

Missing data object

Verify GTM variables are defined

Performance & security

Content Security Policy (CSP)

If your site uses CSP headers, add these directives:

Content‑Security‐Policy:
  script‑src 'self' https://static.redeal.se;
  connect‑src 'self' https://*.redeal.se;

Without these directives, the script will be blocked by the browser.

Script loading strategy

The Voyado script uses async loading to minimise performance impact:

a.async=1;  // Script loads asynchronously

Benefits:

  • Non‑blocking: Page rendering continues while script loads

  • Fast: Script hosted on CDN with global distribution

  • Cached: Browser caches script for subsequent visits

Performance Impact:

  • Initial load: ~15‑25 KB (minified and gzipped)

  • Subsequent loads: 0 KB (cached)

  • Page load delay: <50 ms on average

Best practices

Do:

  • Load script on all relevant pages (cornerwidget is reusable)

  • Use async loading (included in implementation)

  • Implement proper CSP directives

  • Test on staging before production

  • Monitor console for errors after deployment

Don’t:

  • Block page rendering waiting for script

  • Load script multiple times on same page (use conditional checks for SPAs)

  • Hardcode customer data in JavaScript (security risk)

  • Skip testing on different browsers

  • Forget to update CSP when implementing

Data privacy

Email handling:

  • Emails are transmitted over HTTPS

  • Never expose emails in URLs (use POST data)

  • Comply with GDPR/privacy regulations in your region

  • Inform users about data collection in your privacy policy

Session data:

  • Script uses local storage and session storage

  • Data is stored client‑side only

  • Use ?voyado‑clear to manually clear stored data

Browser compatibility

The script is compatible with:

  • Chrome (latest)

  • Firefox (latest)

  • Safari (latest)

  • Edge (latest)

  • Mobile browsers (iOS Safari, Chrome Mobile)

Not supported:

  • Internet Explorer 11 and earlier

Additional resources

Onsite Manager: Configure onsite messages, sites/domains and view analytics

Chrome Extension: Download here

GTM Documentation: Google Tag Manager Help

Voyado Support: Contact your Voyado representative for technical assistance

Need help?

If you have questions or encounter issues not covered in this guide, reach out to Voyado support or your Voyado representative.