Form tracking: SPAs (Single Page Applications)

Updated by Aleksandar Grbic

Tracking events with Dreamdata in a Single Page Application (SPA) depends on the specific SPA framework being used. This article cannot cover every possible framework, but it will provide examples from popular libraries/frameworks, such as React and Angular.

Since there isn't a modern SDK available for seamless installation and import (using any JavaScript module systems), you'll need to manually incorporate our Analytics script into your main index.html file or a template. The location for injecting the script may vary depending on the specific library or framework used. However, most modern UI tools generally have a primary index.html page where the app is rendered, making it a suitable place for script insertion.

It's important to note that, unlike most other methods for configuring Dreamdata analytics and form tracking, this approach necessitates the involvement of a developer with access to the codebase. It cannot be implemented through Google Tag Manager (GTM) or our Auto Identify script.

Setting up the Analytics script:

  1. In your Dreamdata application, navigate to Data Platform > Sources > Javascript (Web Tracking) Source.
  2. Click on the "Copy Script" button.
  3. Make sure to remove call from the end of the script you copied, as your application's router will be doing these calls when the pathname changes.
  4. Paste the copied script into your main app's HTML page, e.g., the index.html file in the root directory for a React CRA. Place the script right before the closing </head> tag.

At this point, should be globally accessible in your app. You now have access to various tracking methods, such as analytics.track, analytics.identify, and, which we will discuss further in the following sections.

Tracking view (route) changes


In SPAs, different views are rendered instead of loading new HTML pages for each URL change. This process is typically managed by a third-party library, like react-router-dom or similar.

Here's an example of tracking view changes in modern React Application:

// React example that uses useLocation hook from react-router-dom
const location = useLocation();
useEffect(() => {;
}, [location.pathname]);

This effect has the location as a dependency, and it calls whenever the URL pathname changes.


The Angular example is similar to the previous React.js example:

// Implement the OnInit interface for your AppComponent:
@Component({ // ... })
export class AppComponent implements OnInit { // ... }

// Subscribe to the router's events and filter for NavigationEnd events, then call with the current route:

constructor(private router: Router) {}
ngOnInit() { => {
if (event instanceof NavigationEnd) {;


In Vue.js, you can achieve a similar functionality to handle router events and call an analytics function when navigation ends. Here’s how you can implement this in a Vue.js component using Vue Router. This of course has to be done in some centralised place in your application where you are listening for route changes.

import { onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';

export default {
name: 'YourComponentName',
setup() {
const router = useRouter();
onMounted(() => {
router.afterEach((to, from) => {;


As mentioned at the beginning of this guide, we cannot cover implementations for every modern UI framework or library. However, the concept should be clear enough, regardless of the framework you use. Simply "hook" into the appropriate router for that specific tool and listen for route changes.

Tracking forms

Although there is a brief section on tracking forms with our Analytics script, it's helpful to provide a straightforward example to guarantee a mutual understanding.

In a contemporary application, it's common to encounter a form accompanied by an onSubmit handler.

export default function FormExample() { 
const [email, setEmail] = useState("");

const handleSubmit = (e) => {

// this will be based on whatever your form does // e.g. book-a-demo

// How you get an email from your form can vary
// and can be done in tens of different ways
// regardless, you'll somehow get a value of an email from a form
// and pass it to our identify

analytics.identify(null, { email });

return (
<div className="App">
<form onSubmit={handleSubmit}>
<input name="email" placeholder="email" type="email" onChange={(e) => setEmail(} />
<button type="submit">Submit</button>
</div> );

This is just a React.js example and illustrates how you would do this in a modern UI library. No matter what you use, you will have a handler for your form. In this scenario, whatever you form does, you will include analytics.track and analytics.identify as part of it.

This concludes our guide on using Dreamdata tracking with Single Page Applications (SPAs). If you have further questions or need clarification on any aspect of this guide, please feel free to contact us.

How did we do?