Articles on: Developer Documentation

UserLoop SDK

UserLoop SDK Integration Guide


The UserLoop SDK lets you embed survey and quiz experiences anywhere on your website so you can capture feedback and transactional context right alongside customer journeys. This guide walks through the core integration steps, explains how to pass customer and order data, and highlights advanced capabilities for production deployments.


Quick Start


Copy-Paste Embed (easiest way)

Drop the snippet below anywhere you want the survey to appear. Replace YOUR_SURVEY_ID with the ID from the UserLoop dashboard and you're done—no extra setup required.


<!-- UserLoop Survey Embed -->
<div id="userloop_survey"></div>
<script>
(function () {
var SURVEY_ID = 'YOUR_SURVEY_ID';
var TARGET_ID = 'userloop_survey';

function start() {
var target = document.getElementById(TARGET_ID);
if (!target) return;
UserLoop(SURVEY_ID, target).init();
}

if (window.UserLoop) {
start();
return;
}

var script = document.createElement('script');
script.src = 'https://cdn.userloop.io/sdk-2/userloop.js';
script.async = true;
script.onload = start;
document.head.appendChild(script);
})();
</script>


When you need more control

If you prefer to manage script loading yourself, or you need to toggle advanced options such as email_collection or branding, initialise the SDK manually once the DOM is ready:


<script async src="https://cdn.userloop.io/sdk-2/userloop.js"></script>
<div id="userloop_survey"></div>
<script>
window.addEventListener('DOMContentLoaded', function () {
const SURVEY_ID = 'YOUR_SURVEY_ID';
const TARGET_ELEMENT = document.getElementById('userloop_survey');
const CONFIG = {
email_collection: true,
expanded_mode: false,
userloop_branding: false,
};

const userLoopInstance = UserLoop(SURVEY_ID, TARGET_ELEMENT, CONFIG);
userLoopInstance.init();
});
</script>


Add optional customer and transaction context by passing a fourth argument when available (see Passing Customer and Transaction Data).


Initializer Anatomy


UserLoop(surveyId, targetElement, config, context) returns an instance with init, refresh, setSurveyId, and mount methods. Below is a summary of the most common configuration options for production use:


Option

Type

Description

email_collection

boolean

Displays an email capture step when the survey requires it and the customer record lacks an email address.

expanded_mode

boolean

Forces the survey into an expanded layout that stretches to the width of its container. Useful for wider marketing pages.

userloop_branding

boolean

When true, shows the "Powered by UserLoop" footer if your survey has branding enabled.

surface

string

Identifies the integration surface for analytics (defaults to sdk). Update if you manage multiple surfaces.


The fourth context argument is optional. Pass customer and transaction objects when you have them; the SDK defaults to empty objects when they are omitted.


Passing Customer and Transaction Data


Enriching responses with customer and order context makes it easier to segment and act on feedback. When you're ready, populate any of the fields below before calling init() or refresh(). Each field is optional—provide only what you have.


Customer Fields

  • email: Customer email address
  • id: Internal customer identifier (e.g., CRM or platform ID)
  • firstName, lastName: Optional name fields
  • phone: Optional phone number


Transaction Fields

  • transaction_id: Order or transaction identifier
  • order_creation_date: ISO-8601 timestamp (2024-03-01T10:05:00.000Z)
  • total: Numeric order total
  • currency: ISO currency code (e.g., USD)
  • coupon_code: Applied discount code
  • utm_source, utm_medium, utm_campaign, utm_content, utm_term: Attribution parameters
  • platform: Platform name (e.g., Shopify, WooCommerce, Custom Storefront)
  • source: Traffic source descriptor (website, email, etc.)
  • products: Array of { id, name, product_url } entries describing purchased items


When additional fields become available (for example, after checkout completes), update the objects and call userLoopInstance.refresh() to pull the latest survey configuration while preserving current state when possible.


const customer = {
email: order.email,
id: order.customerId,
};

const transaction = {
transaction_id: order.id,
total: order.total,
currency: order.currency,
order_creation_date: order.createdAt,
products: order.items.map((item) => ({
id: item.productId,
name: item.title,
product_url: item.url,
})),
};

// Later, pass the context when initializing or refreshing
const userLoopInstance = UserLoop(SURVEY_ID, TARGET_ELEMENT, CONFIG, {
customer,
transaction,
});
userLoopInstance.init();


Platform Examples


Shopify Liquid

<div id="userloop_survey"></div>
<script>
const SURVEY_ID = 'YOUR_SURVEY_ID';
const TARGET_ELEMENT = document.getElementById('userloop_survey');
const CONFIG = { email_collection: true };

const customer = {
email: '{{ customer.email | escape }}' || '',
id: '{{ customer.id }}' || '',
};

const transaction = {% if order %}{
transaction_id: '{{ order.order_number }}',
total: {{ order.total_price | default: 0 }},
currency: '{{ order.currency | escape }}',
order_creation_date: '{{ order.created_at | date: "%Y-%m-%dT%H:%M:%S.%LZ" }}',
coupon_code: '{{ order.discount_code | escape }}',
products: [
{% for line_item in order.line_items %}
{
id: '{{ line_item.product_id }}',
name: '{{ line_item.title | escape }}',
}{% unless forloop.last %},{% endunless %}
{% endfor %}
],
platform: 'Shopify',
source: 'website',
}{% else %}{}{% endif %};

document.addEventListener('DOMContentLoaded', function () {
const userLoopInstance = UserLoop(SURVEY_ID, TARGET_ELEMENT, CONFIG, {
customer,
transaction,
});

userLoopInstance.init();
});
</script>


WooCommerce (PHP Template)

<div id="userloop_survey"></div>
<script>
const SURVEY_ID = 'YOUR_SURVEY_ID';
const TARGET_ELEMENT = document.getElementById('userloop_survey');
const CONFIG = { email_collection: true };

const customer = {
email: '<?php echo esc_js( wp_get_current_user()->user_email ?? '' ); ?>',
id: '<?php echo esc_js( wp_get_current_user()->ID ?? '' ); ?>',
};

<?php
$transaction_payload = [];
if ( function_exists( 'wc_get_order' ) && isset( $_GET['order-received'] ) ) {
$order = wc_get_order( intval( $_GET['order-received'] ) );
if ( $order ) {
$transaction_payload = [
'transaction_id' => $order->get_id(),
'currency' => $order->get_currency(),
'total' => $order->get_total(),
'order_creation_date' => $order->get_date_created()->date( 'c' ),
'products' => array_map(
fn ( $item ) => [
'id' => $item->get_product_id(),
'name' => $item->get_name(),
],
$order->get_items()
),
'platform' => 'WooCommerce',
'source' => 'website',
];
}
}
?>

const transaction = <?php echo wp_json_encode( $transaction_payload ); ?>;

document.addEventListener('DOMContentLoaded', function () {
const userLoopInstance = UserLoop(SURVEY_ID, TARGET_ELEMENT, CONFIG, {
customer,
transaction,
});

userLoopInstance.init();
});
</script>


Advanced Capabilities


  • Refresh with new data: If customer or transaction details change after initialization (for example, when a user completes checkout), update your local objects and call userLoopInstance.refresh() to rebuild the survey with the latest context.
  • Switch surveys dynamically: Use userLoopInstance.setSurveyId('NEW_SURVEY_ID') to load a different survey into the same container without reloading the page.
  • Remount after DOM changes: On single-page applications, call userLoopInstance.mount() when route transitions replace the container element so the SDK can reattach itself.
  • Collect emails conditionally: Combine email_collection: true with a populated customer.email to skip the email step for known customers while still collecting contact info for anonymous visitors.


Best Practices

  • Load the SDK once per page and reuse the returned instance rather than creating duplicates.
  • Keep your container element stable; if your framework re-renders nodes, call mount() after the new node is in place.
  • Validate that the SURVEY_ID configured in production points to the correct environment-specific survey.
  • Test the full survey and quiz flow (including any recommendation steps configured in the dashboard) to ensure responses and follow-up logic behave correctly.
  • Monitor network requests in your browser developer tools to confirm the SDK can reach https://userloop.io endpoints from your environment.


Updated on: 19/09/2025

Was this article helpful?

Share your feedback

Cancel

Thank you!