Single-page Application (SPA) Guide (Developer)
Follow this guide to learn how to implement Appcues on your Single Page Application.
Table of Contents
Appcues is supported on your Single Page Application
Looking for the most up-to-date installation guides? Check out our Installation Guide in our Studio app.
Single-page Applications (SPAs) only trigger a full page load when they are first loaded. Otherwise, navigating across pages in your app doesn't trigger a page load. There are two ways Appcues can be notified of these page changes so that Appcues can determine the correct content to show to the end-user:
- Appcues can automatically detect page changes. Note this is the default and no action is needed if you followed our installation guide after May 23, 2022.
- Appcues can be manually notified of page changes via the Appcues.page() call.
Automatic detection of page changes
Note: You can ignore this section if you followed our installation guide after May 23, 2022. To enable automatic detection of page changes, all that is required is to set the "enableURLDetection" setting to true in the window.AppcuesSettings object. The following code needs to be placed directly above the script tag that loads the Appcues script:
<script type="text/javascript">
window.AppcuesSettings = {
enableURLDetection: true
};
</script>
<script src="//fast.appcues.com/ACCOUNT_ID.js"></script>
And that's it. With this setting enabled Appcues will automatically detect page changes.
React and React-router Manual Instructions
There may be some cases where automatic page change detection is not desired. If you would like to disable this, set the enableURLDetection setting to false in the above snippet. Below are instructions on how to install specific to your SPA. For detailed instructions on installing Appcues in React, Angular, Vue, and other application frameworks please check out the frameworks installation documentation in the Appcues Studio.
Appcues implementation best practice:
Ensure that your Appcues.identify(); is called prior to the execution of the first page() call within your Appcues implementation code.
If not implemented this way, your end users could experience a delay due to events buffering while waiting on a user to be identified.
Appcues.identify() call.
In your application, you will most likely have some sort of user authentication where your users are identified. While you can include the Appcues.identify() into your html file, to avoid over-identifying your users, you might want to call it once somewhere user authentication occurs in your application.
Here's an example with Firebase auth:
import React, {Component} from 'react';
import firebase from 'firebase';
class App extends Component {
componentWillMount() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// now that we have a reference to the user, we can identify them with Appcues
window.Appcues.identify(user.uid, {
email: user.email,
displayName: user.displayName
});
}
})
}
render() {
// render function
}
}
Appcues.page() call.
You can call the Appcues.page() function to tell Appcues when you're on a new page/view. This causes Appcues to look at the current page and user properties and check if there's any content that should be shown. So ideally in a React app you'll call Appcues.page() any time there's a navigation event or new view.
What does this look like in React? Well, if you're using react-router v3, then you might use the onUpdate event:
<Router onUpdate={() => window.Appcues.page()}
If you are using version v4 or above, then you might use a useEffect listening for location changes:
import { useLocation } from “react-router-dom”;
import { useEffect } from “react”;
let location = useLocation();
useEffect(() => {
window.Appcues.page()
}, [location]);
AngularJS Manual Instructions
Appcues.page() call.
You can call the Appcues.page() function to tell Appcues when you're on a new page/view. This causes Appcues to look at the current page and user properties and check if there's any content that should be shown. So ideally in an Angular app you'll call Appcues.page() any time there's a navigation event or new view.
What does this look like in Angular? Well, if you're using the angular ui-router, then you may be tempted to use the $viewContentLoaded event, since it seems like it would fire after the state has changed and you're on a new "page" in your app. However, this event actually fires before the URL has been updated. You'll end up with Appcues checking the previous page's URL, not the one you just navigated to. One solution we've found is to make use of the $locationChangeSuccess event, which is "broadcasted after a URL was changed," according to the docs. This will ensure that the URL that Appcues checks is the correct (i.e. current) one.
To debug your Appcues.page call for single page apps, publish something to just your `user_ID` and see if the flow shows automatically. If you need to refresh the page in order for Appcues to appear, that indicates it's in the wrong place. Let us know and we can take a look for you.
Here's an example!
// For example, in your App.js:
angular.module('yourapp').run(function($rootScope, $window) {
$rootScope.$on('$locationChangeSuccess', function() {
if ($window.Appcues) {
$window.Appcues.page();
}
});
});
Angular 2, 4, 5 Manual Instructions
Appcues.page() call.
You can call the Appcues.page() function to tell Appcues when you're on a new page/view. This causes Appcues to look at the current page and user properties and check if there's any content that should be shown. So ideally, you'll call Appcues.page() any time there's a navigation event or new view.
What does this look like in Angular 2, 4 & 5? We suggest using the NavigationEnd event to trigger Appcues.page():
this.router.events
.subscribe((event) => {
if (event instanceof NavigationEnd) {
window.Appcues && window.Appcues.page();
}
});
Note: if you're using Typescript and are receiving the error Property 'Appcues' does not exist on type 'Window & typeof globalThis', you will need to ensure Appcues is declared as a global variable. One way to do this is with the following snippet:
declare global {
interface Window { Appcues: any; }
}
Special cases where automatic page change detection may not be desired
Sites that use query parameters to update the state of the page but not to indicate separate pages may not want to enable automatic page change detection. This will result in page changes being sent to Appcues for every query parameter change, which may not be the desired behavior. For example, a page that uses query parameters to indicate a search filter may update its search parameter with each keypress (e.g. https://app.example.com/results?search=test). Even though the page is the same, the URL has changed to include the search query parameter. In this case, Appcues would see this as a new page change, and would stop any in-progress experiences and re-check for content to show the end-user. To handle these cases, follow the instructions above for Manually notifying Appcues of page changes
Looking for more information on how to build Appcues experiences on SPAs with dynamically generated elements? Have a look at our auto-generated (Dynamic) selectors document.