James

James

Last updated on Jul 23, 2026

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.

(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); })();

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:

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(); });

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.
quiz_mode boolean Enables quiz mode. After the respondent answers all questions, the SDK calls UserLoop's AI recommendation engine and displays personalized product suggestions.
quiz_api_key string API key for the quiz recommendation service. Required when quiz_mode is true.
allow_restart boolean Shows a "Restart survey" button on the thank-you page, letting respondents retake the survey.
auto_answer_first_question string Pass an answer_id to automatically select and submit the first question. Useful for post-purchase flows where the trigger determines the first answer.

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

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(); });

WooCommerce (PHP Template)

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(); });

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.
  • Quiz mode with product recommendations: Set quiz_mode: true and provide a quiz_api_key to enable AI-powered product recommendations. After all questions are answered, the SDK displays personalized product cards with images, prices, AI-generated reasoning, and "View Product" links with UTM tracking.
  • Auto-answer the first question: Pass auto_answer_first_question: 'ANSWER_ID' to automatically select and submit the first answer. This is useful for email campaign integrations where the link click itself determines the first response.
  • Allow survey restarts: Set allow_restart: true to add a "Restart survey" button on the thank-you page, letting respondents retake the survey without reloading the page.

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.