Userflow.js Reference
Userflow.js should be installed in your web app or website. It's responsible for identifying your users with Userflow and showing flows, checklists and more when appropriate.
Follow us on Twitter for Userflow.js announcements.
Quick links
Quick access to methods that you'll probably need:
Method | Purpose |
---|---|
userflow.init() | Initialize Userflow.js with your Token |
userflow.identify() | Identify a user |
userflow.group() | Associate current user with a group |
userflow.track() | Track an event |
Installation
Install userflow.js via npm
Install Userflow.js via npm:
npm install userflow.js
Or, install via Yarn
yarn add userflow.js
We recommend using the userflow.js npm package as it offers the best developer experience:
See also Userflow.js installation for an alternative installation method via a plain <script>
tag.
Quick start
import userflow from 'userflow.js'
userflow.init('<USERFLOW_TOKEN>')
userflow.identify('<USER_ID>', {
name: '<NAME>',
email: '<EMAIL>',
signed_up_at: '2019-06-14T16:25:49Z'
})
Put this code in your app where it has access to the current user's information.
Replace all placeholders (e.g. <USERFLOW_TOKEN>
and <USER_ID>
) with real values.
Grab your Userflow.js Token under Settings -> Environments. Note that if you have multiple environments (e.g. Production and Staging) that each environment has a unique token.
The userflow object
Import the
userflow
object:
import userflow from 'userflow.js'
The userflow.js
npm package is a thin wrapper around the real Userflow.js, which is loaded from our CDN. This way, you can interact with the imported userflow
object immediately. On the first method call, the real Userflow.js will automatically be loaded (asynchronously) and injected into the current page. Method calls are automatically queued by the userflow
object.
The real Userflow.js script is a small script (currently <16 KB gzipped) that contains the bare minimum to identify users and check if they have any active flows. Additional UI code and styles will only load if the user has any active flows. This is to have as small an impact on your page's load time as possible. For legacy browsers (that don't support ES2020 features), a legacy script is loaded instead.
If you've installed Userflow.js via a <script>
tag, you can access the object via window.userflow
. Just be careful that it may not be loaded yet (which is why the userflow.js npm package is recommended!).
Attributes
Example of using all the possible data types (these will all be inferred as expected):
userflow.identify('123456', {
string: 'Just a string',
always_true: true,
always_false: false,
integer_number: 42,
decimal_number: 1234.56,
used_datetime_at: '2019-12-03T12:34:56.123Z'
})
Remove an attribute:
userflow.updateUser({
phone_number: null
})
Explicitly setting
data_type
:
userflow.identify('123456', {
// This will be consumed as a string, even though its value
// is a number here
phone: {set: 12345678, data_type: 'string'}
})
Using
set_once
:
userflow.identify('123456', {
coupon_code: {set_once: generate_onetime_coupon_code()}
})
Using
add
andsubtract
:
userflow.updateUser({
widget_count: {add: 1},
total_revenue: {add: 1234.56},
days_left: {subtract: 1}
})
Several methods accept an attributes
dictionary, which represents arbitrary information about objects such as users and events. You can use this to, for example, store a user's name or their date of sign-up, or to decorate events with e.g. which billing plan was selected. These attributes can then be used within Userflow to segment users or personalize their flows.
When updating objects with attributes, the values in the attributes
dictionary can be literal values (string, boolean, number), which just sets the attributes to the given values.
If an attribute value is null
, the attribute will be removed from the object.
You can also specify an operation object instead of a literal value. This operation object can contain the following keys (note that exactly one of set
, set_once
, add
or subtract
must be set):
Key | Description |
---|---|
set |
String/number/boolean - Sets the attribute to this value. This is the same as using literal values, except this way you can explicitly set the data_type , too. |
set_once |
String/number/boolean - Sets the attribute to this value, but only if the user doesn't already have a value for this attribute. |
add |
Number - Adds this value to the attribute's current value. If the user does not have the attribute yet, the given number will be added to 0 . Only works on number attributes. |
subtract |
Number - Same as add , but subtracts the given number instead. To subtract, you either supply a negative number to add , or a positive number to subtract . |
data_type |
String - Explicitly tells Userflow what data type to use. Can be one of: string , boolean , number , datetime . You usually don't have to set this, as Userflow will infer the right data type depending on the values you supply. |
Attribute names (they keys of attributes
objects) must consist only of a-z, A-Z, 0-9, underscores, dashes and spaces. We recommend using snake_case
everywhere though. Attributes' human-friendly display names (e.g. "Signed Up" for signed_up_at
) can also be configured in the Userflow UI.
Setup
init()
userflow.init('bmztslyu5zgujmcvna34mggj44')
Initializes Userflow.js to target your company. Must be called once (per page load) before you make any other call.
Parameters
Parameter | Description |
---|---|
token |
String, required - Your Userflow.js Token, which you can find under Settings -> Environments. Note that if you have multiple environments (e.g. Production and Staging) that each environment has a unique token. |
Users
Users are the people using your application. Userflow keeps track of your users, so we can determine which flows to show them, and remember which flows they've already seen.
identify()
Example of sending the recommended attributes:
userflow.identify('123456', {
name: 'Jane Smith',
email: 'jane@example.com',
signed_up_at: '2019-06-14T16:25:49Z'
})
Minimal example of sending only userId:
userflow.identify('123456')
Identifies the current user with Userflow. You should call this once on any page load where a user is signed in.
If attributes
is set, they will be merged into the user's existing attributes in Userflow. Any attributes you leave out will be left as-is in Userflow.
It's up to you which attributes you want to send to Userflow. The only required argument is userId
. Make sure not to send any sensitive data such as passwords. We recommend sending the name
and email
attributes so you can easily tell users apart in Userflow without relying on IDs only, and signed_up_at
, which is often used in flow start conditions.
If the user has any active flows, they will be displayed. If the user matches any flows' start conditions, they may be started.
Parameters
Parameter | Description |
---|---|
userId |
String, required - The user's ID in your database. |
attributes |
Object, optional - Attributes to update for the user. See Attributes. These attributes can be used in flow content and conditions to personalize the user experience. |
Returns
A Promise
that resolves once the identify call succeeds.
identifyAnonymous()
Example of identifying an anonymous user and tagging them with a custom
website_lead
attribute, so they can be targeted by flows:
userflow.identifyAnonymous({
website_lead: true
})
Same as userflow.identify(), except Userflow.js will automatically assign the current user a unique ID. This ID will be stored in the user's localStorage
, and will be reused on reloads.
You should only use this for anonymous users, who are not signed into your app. If they are signed in, please use userflow.identify() with their real user ID.
Parameters
Parameter | Description |
---|---|
attributes |
Object, optional - Attributes to update for the user. See Attributes. These attributes can be used in flow content and conditions to personalize the user experience. |
Returns
A Promise
that resolves once the identify call succeeds.
isIdentified()
userflow.isIdentified() // true or false
Check if a user has been identified.
Returns
true
if userflow.identify
or userflow.identifyAnonymous
has been called. false
otherwise.
updateUser()
Example of updating a user's favorite color:
userflow.updateUser({
favorite_color: 'red'
})
Updates attributes for a user that has already been identified with userflow.identify
since the last page load.
Parameters
Parameter | Description |
---|---|
attributes |
Object, optional - Attributes to update for the user. See Attributes. |
Returns
A Promise
that resolves once the update call succeeds.
reset()
userflow.reset()
Makes Userflow forget about the current user and immediately hides any active flows.
Call this when users sign out of your app.
Groups
Groups are used to group multiple users together. In your business, groups may correspond to e.g. companies, teams or departments.
Like users, groups can have attributes. Events can also be associated with groups.
With groups, you can orchestrate the flows a user sees:
- ...based on behavior of other users in a group. Example: Show a flow if no one in a group has created a "widget" yet.
- ...based on multiple groups that the user is a member of. Example: Show a flow if the group the user is currently working on matches some condition.
Note that the Groups feature is only available in certain plans. Check your Billing page or reach out to us to ask.
group()
Example setting the current group for a user:
userflow.group('987654', {
name: 'Acme Inc.',
plan: 'Premium'
})
Minimal example of sending only groupId:
userflow.group('987654')
Example including membership attributes:
userflow.group(
'987654',
{
name: 'Acme Inc.',
plan: 'Premium'
},
{
membership: {
role: 'owner'
}
}
)
Associates the currently identified user with a group, and optionally updates the group's attributes. You should call this once on any page where the user is working on a specific group. If the user navigates to a different group, simply call userflow.group(newGroupId)
again, and Userflow will switch to using that group instead.
If attributes
is set, they will be merged into the group's existing attributes in Userflow. Any attributes you leave out will be left as-is in Userflow.
Parameters
Parameter | Description |
---|---|
groupId |
String, required - The group's ID in your database. |
attributes |
Object, optional - Attributes to update for the group. These attributes can be used in flow content and conditions to personalize the user experience. |
options |
Object, optional |
options.membership |
Object, optional - Attributes to update for the user's membership of the group. Some attributes neither belong on users, nor on groups. One example is a user's "role". A user can have different roles in different groups. A group's members can have different roles. Attributes like "role" are membership attributes. They can be used in the Userflow UI just like group attributes. |
Returns
A Promise
that resolves once the group call succeeds.
updateGroup()
Example of updating a group's plan:
userflow.updateGroup({
plan: 'Pro'
})
Updates attributes for a group that has already been registered with userflow.group
since the last page load.
Parameters
Parameter | Description |
---|---|
attributes |
Object, optional - Attributes to update for the group. See Attributes. |
Returns
A Promise
that resolves once the update call succeeds.
Events
You can track events for users and groups for analytics purposes or to segment and personalize your flows.
Events tracked via Userflow.js is always associated with the current user. They can optionally be associated with groups, too.
track()
Minimal example of tracking an event when a user activates their subscription:
userflow.track('subscription_activated')
Example with attributes:
userflow.track('subscription_activated', {
plan_name: 'plus',
plan_price: 1234.56
})
Track an even without associating it with the current group:
userflow.track(
'email_changed',
// No attributes
{},
// Options
{
userOnly: true
}
)
Tracks an event related to the currently identified user.
userflow.identify
must have been called before calling track
.
Both event names and attribute names must consist only of a-z, A-Z, 0-9, underscores, dashes and spaces. We recommend using snake_case
everywhere though. Events and attributes' human-friendly display names (e.g. "Subscription Activated" for subscription_activated
) can also be configured in the Userflow UI.
We recommend using event names consisting of a noun and a past-tense verb. Check out this great event naming guide by Segment.
Parameters
Parameter | Description |
---|---|
eventName |
String, required - Name of the event. Examples: subscription_activated , project_created , coworker_invited . See note about event naming below. |
attributes |
Object, optional - Attributes for the event. See Attributes. |
options |
Object, optional - Adjust how the event should be tracked. |
options.userOnly |
Boolean, optional - By default, when userflow.group() has been called, events are associated with both the user and the group. Set userOnly to true to not associate the event with the group. This is useful when the user performs an event that's not group-related, such as changing their own email address. |
Returns
A Promise
that resolves once the track call succeeds.
Flows and content
Content refers to the stuff you build in Userflow, such as flows and checklists. You can manipulate what the current user sees programmatically via Userflow.js.
start()
Start a flow and show it immediately:
userflow.start('89eff72a-d0ae-4be6-b241-1ab04e3da7cc')
Start flow, but only if the user hasn't seen it before:
userflow.start('89eff72a-d0ae-4be6-b241-1ab04e3da7cc', {once: true})
Starts a Userflow content item (flow, checklist etc.) for the currently signed-in user. The content will display immediately.
Use this to programmatically start content when something happens in your app. You could, for example, implement a button called "Show onboarding tutorial again", which users can click after signing up to go through your tutorial again.
Parameters
Parameter | Description |
---|---|
contentId |
String, required - ID of the content to start. You can find the content ID in Userflow on the "Link/Embed" tab. It's also the ID you see in the URL: /app/{company}/content/{contentId} |
options |
Object, optional |
options.once |
Boolean, optional - If set to true , the content will only start if the user has not seen it before. If the user has already seen it before, nothing happens. Defaults to false . |
Returns
A Promise
that resolves once the content has been started.
endAll()
userflow.endAll()
Ends all currently active Userflow content (flows, checklists etc.), if any, for the user. The content will be hidden immediately.
If the user does not have any active content, nothing happens.
Advanced usage
on()
const listener = visible => {
console.log(visible ? 'Flow is visible' : 'Flow was hidden')
}
userflow.on('flowvisibilitychange', listener)
// ...later, when no longer needed:
userflow.off('flowvisibilitychange', listener)
Registers an event listener to be called when the given eventName
is triggered.
Parameters
Parameter | Description |
---|---|
eventName |
String, required - Name of event to listen for. See list of supported events. |
listener |
Function, required - Function to call when the event is triggered. Depending on the eventName , listener may receive a single argument providing more details about the event. |
off()
userflow.off('flowvisibilitychange', listener)
Removes an event listener previously registered with userflow.on
.
Parameters
Parameter | Description |
---|---|
eventName |
String, required - Name of event. See list of supported events. |
listener |
Function, required - Function to that was added with userflow.on . |
registerCustomInput()
Example HTML markup (in your app):
<label>Fruit</label>
<div class="combo-box">
<div class="combo-box-value">Banana</div>
<div class="combo-box-trigger">..icon..</div>
</div>
Example Userflow.js configuration:
userflow.registerCustomInput('.combo-box-value')
It's now possible to make conditions in the Flow Builder using the value of inputs labeled with
Fruit
. It works just as if the markup had used an<input>
like this:
<label>Fruit</label>
<div class="combo-box">
<input type="text" value="Banana" />
<div class="combo-box-trigger">..icon..</div>
</div>
Example of using the
getValue
function:
userflow.registerCustomInput('.combo-box', el => {
const valueEl = el.querySelector('.combo-box-value')
return (valueEl && valueEl.textContent) || ''
})
In this case, Userflow will return
Banana
as the value, and leave out the..icon..
part.
Teaches Userflow.js to treat HTML elements in your app as custom text inputs.
This is useful if, for example, you use combo boxes and want Userflow to treat them like regular <input>
elements. Instead of reading a value
property (as we do with input
elements), the text content of the custom input element is used instead. Or, you can supply a custom getValue
function to customize how to read a string value from an element.
Note that you can call this function multiple times to support multiple kinds of custom inputs.
Parameters
Parameter | Description |
---|---|
cssSelector |
String, required - Valid CSS selector that matches your custom input element. |
getValue |
Function, optional - If set, should be a function that takes an element and returns a string representing the custom input's current value. If not set, Userflow will default to using the text content of the whole element. |
setCustomNavigate()
Example, where
myRouter
is a fictive router object:
userflow.setCustomNavigate(url => myRouter.push(url))
Example with React Router app:
// File: history.js
import {createBrowserHistory} from 'history'
export default createBrowserHistory()
// File: index.js
import {Router} from 'react-router-dom'
import history from './history'
import App from './App'
ReactDOM.render(
<Router history={history}>
<App />
</Router>,
document.body
)
// File: wherever-you-load-userflow.js
import history from './history'
// ...
userflow.setCustomNavigate(url => history.push(url))
// ...
By default, when performing Go to page actions, Userflow will cause full page loads using window.location.href = url
.
Call this function to override this behavior.
This is useful for single page applications using in-app navigation through the window.history
API.
Parameters
Parameter | Description |
---|---|
customNavigate |
Function or null , required - A function taking a single string url parameter. Or null to turn off and use default behavior. |
setCustomScrollIntoView()
Example making Userflow always scroll tooltip targets to the vertical center of the viewport:
userflow.setCustomScrollIntoView(el => {
el.scrollIntoView({
behavior: 'smooth',
block: 'center'
})
})
For reference, this is how the default works:
userflow.setCustomScrollIntoView(el => {
el.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
})
})
Override how Userflow.js scrolls elements into view, for example when showing a tooltip pointing to an element outside the viewport.
By default, scrolling will be animated and only happen if the element is outside the viewport.
Parameters
Parameter | Description |
---|---|
customScrollIntoView |
Function or null , required - A function taking a DOM Element . Or null to turn off and use default behavior. |
setUrlFilter()
Example removing all query parameters:
userflow.setUrlFilter(url => {
const parsed = new URL(url)
parsed.search = ''
return parsed.toString()
})
// Full URL:
// https://example.com/dashboard?q=secret&sort_by=name
// Filtered URL:
// https://example.com/dashboard
Example removing just a specific
?q
query parameter:
userflow.setUrlFilter(url => {
const parsed = new URL(url)
parsed.searchParams.delete('q')
return parsed.toString()
})
// Full URL:
// https://example.com/dashboard?q=secret&sort_by=name
// Filtered URL:
// https://example.com/dashboard?sort_by=name
Userflow passes the user's current URL to Userflow's servers. We use this for conditions matching the current URL and to automatically track page views. By default, we use the full URL including domain, path (/...
), query parameters (?...
) and fragment (#...
).
If your app's URLs contain sensitive information that should never leave the browser, you can customize URLs before they leaves the browser, e.g. to filter out sensitive parts.
Tip: If you want to verify that your URL filter works properly, try visiting a page with a filtered URL in your app. Then go to Userflow's Users tab and find your own user. Under Activity feed, click the most recent Page Viewed event to expand its attributes. Look for the Page URL attribute.
Parameters
Parameter | Description |
---|---|
urlFilter |
Function or null , required - A function taking a single string url parameter that returns a filtered URL (as a string). Or null to turn off and use default behavior of passing the full URL. |
setInferenceAttributeFilter()
Example of ignoring all ids starting with
auto-
:
userflow.setInferenceAttributeFilter(
'id',
// Returns true if the id does not start with `auto-`
id => !id.startsWith('auto-')
)
Example of using an array containing both a function and a regular expression:
userflow.setInferenceAttributeFilter('id', [
// Ignore ids starting with `auto-`
id => !id.startsWith('auto-'),
// Only consider ids consisting of a-z and dashes
/^[a-z-]+$/
])
Restricts HTML element attribute values from being used for element inference.
By default, Userflow.js may use all values of attributes configured with userflow.setInferenceAttributeNames. The only exception is that, by default, id
s ending in numbers will be ignored. This is to support some dynamic IDs out-of-the-box. The same logic is applied to data-id
attributes.
Parameters
Parameter | Description |
---|---|
attributeName |
String, required - The attribute name the filter should apply to. Example values: id , data-testid . |
filters |
Function, RegExp instance, or an array of functions or RegExp instances, required - When Userflow considers an attribute value, it'll be passed through all the given filters before we decide to use it. Filter functions are called with the attribute value and must return a truthy value to allow Userflow.js to use it. Regular expressions must match the attribute value to allow Userflow.js to use it. You can pass a single function, a single regular expression, or an array with a mix. |
setInferenceAttributeNames()
Example of overriding the list of attribute names to use:
userflow.setInferenceAttributeNames(['name', 'placeholder', 'data-testid'])
Tells Userflow.js which HTML element attributes may be used for element inference.
By default, Userflow.js may use the values of the following element attributes for inference:
data-for
data-id
data-testid
data-test-id
for
id
name
placeholder
role
Parameters
Parameter | Description |
---|---|
attributeNames |
Array of strings, required - Names of HTML attributes that Userflow may use for element inference. |
setInferenceClassNameFilter()
Example of ignoring dynamic class names starting with
css-
:
userflow.setInferenceClassNameFilter(
// Returns true if the class name does not start with `css-`
cls => !cls.startsWith('css-')
)
Restricts CSS class names from being used for element inference.
By default, Userflow.js comes with a set of filters that attempt to exclude dynamic class names, such as ones starting with css-
, which may change from version to version of your own app, and therefore aren't reliable.
Parameters
Parameter | Description |
---|---|
filters |
Function, RegExp instance, or an array of functions or RegExp instances, required - When Userflow considers a class name, it'll be passed through all the given filters before we decide to use it. Filter functions are called with the class name and must return a truthy value to allow Userflow.js to use it. Regular expressions must match the class name to allow Userflow.js to use it. You can pass a single function, a single regular expression, or an array with a mix. |
setScrollPadding()
Example, if you have a 50px tall sticky header:
userflow.setScrollPadding({top: 50})
Example, if you have a 50px tall sticky header and a 20px tall sticky footer:
userflow.setScrollPadding({top: 50, bottom: 20})
To turn off again:
userflow.setScrollPadding(null)
By default, when Userflow needs to scroll an element (e.g. the target of a tooltip) into view, we use the built-in Element.prototype.scrollIntoView
method. This doesn't work well with sticky header/footers, since the element may be scrolled within the browser's viewport, but still be below the sticky header/footer.
To get around this, you can instruct Userflow to scroll just a little further in any direction in order to get the element inside the viewport and away from the sticky header/footer.
Note that this behavior will not work, and we'll fall back to plain Element.prototype.scrollIntoView
, if the target element is nested within other scroll containers.
Parameters
Parameter | Description |
---|---|
scrollPadding |
Object or null - Set to an object to use scroll padding. Set to null to turn off again. |
scrollPadding.top |
Number, optional - Padding from the top of the viewport (pixels) |
scrollPadding.right |
Number, optional - Padding from the right of the viewport (pixels) |
scrollPadding.bottom |
Number, optional - Padding from the bottom of the viewport (pixels) |
scrollPadding.left |
Number, optional - Padding from the left of the viewport (pixels) |
Client-side events
These are events that you can subscribe to via userflow.on().
Note that these events are not related to the events you track with userflow.track
.
checklistEnded
Store in own database when a specific checklist is closed:
userflow.on('checklistEnded', event => {
if (event.checklist.id === '52e7e20d-f351-4528-9400-95de7b4ff6be') {
myDb.update({getStartedChecklistClosed: true})
}
})
Emitted when a checklist is permanently closed/dismissed. This typically happens when the user clicks "Dismiss checklist".
Event properties
When the event is emitted, listeners receive a single object argument with the following keys:
Key | Description |
---|---|
checklist |
Content object - Checklist that ended. |
flowEnded
Emitted when the flow is permanently closed. This typically happens due to a user action, such as by clicking the X or clicking a button with a "Close" action.
Event properties
When the event is emitted, listeners receive a single object argument with the following keys:
Key | Description |
---|---|
flow |
Content object - Flow that ended. |
Object interfaces
This section contains definitions of objects used in various methods and events.
Content object
Represents a content item (flow/checklist).
Properties
Key | Description |
---|---|
id |
String |
type |
String - Indicates the type of content. One of: checklist , flow |