Getting Started With The Beacon API
The Beacon API is a web API avalible for developers to implement into their application. View full list of web APIs here. The Beacon API
is a Web API useful for:
- Analytics
- Diagnostics
Why not fetch
or XMLHttpRequest
?
As stated in the MDN Docs, the unfortunate truth is User Agents will typically ignore XMLHttpRequest
made with an unload handler. Which is the handler we want to use before an individual leaves/navigates away from the page.
Overview?
In this article we will building a very basic analytics tracking library. The objective is to:
- Create a backend to capture the data and serve our index.html page
- Track what element the end user clicked on and record it with a time stamp.
- Store the data that is being generated on each click to a global object to store.
- Before refreshing, or leaving the page send the data stored in the global object to the backend using the
sendBeacon()
method provided by the Beacon API.
Setup
- First, make sure you have Node.js installed into your system.
- Once Node is installed on your computer clone the project files:
git clone https://github.com/BboyAkers/WebAPIs.git
- Navigate to the start folder. WebAPIs->beaconAPI->start
- Open the terminal and install the dependencies
npm install
We've installed two dependencies.body-parser
andexpress
.- We will be using
body-parse
to parse the incoming POST request from our frontend. -
express
is the backend web framework we will be using to setup our server.
- We will be using
Setting Up Our Server
Objective:
- Setup a basic express server
- Serve our
index.html
inside of ourpublic/
folder to the frontend
Navigate to the server.js file in the base directory of the start/
folder.
First we want to setup our basic express server
server.js
const express = require("express");
const app = express();
app.listen(8081, () => console.log("Listening on 8081"))
In your terminal run:
node server.js
We've now successfully setup our basic express server!
When we navigate to localhost:8081
we should see the message: Cannot GET /
.
What do we have to do to eliminate this error?
- We need to find something for our express app to do on
/
our base directory.- For example, serving our index.html to the frontend.
How do we serve our index.html from the servers side?
We are going to use express static to serve the index.html, which is a static file. Our index.html file is located in the public/
folder. When using express static
we need to establish what folder we want to use to serve our static content. Since all of our static content including our index.html is inside our public folder, we are going to specify the "public" folder.
app.use(express.static('public'))
Our server.js file should look quite similar to this:
const express = require("express");
const app = express();
//serving the static content inside our public folder
app.use(express.static('public'))
app.listen(8081, () => console.log("Listening on 8081"))
Navigate to localhost:8081/index.html
in your browser.
You should now see our app.
Congratulations! You've successfully setup the server!
Setting Up Our Analytics.js File
Objective:
- Tie the
analytics
function on winow.onload window.unload. - Create an event that:
- detects what element a user clicks on when visiting the page
- Create a timestamp to record what time the user clicked that element
- Store the object that holds the clicked element and the timestamp into a global object.
- Before leaving the page send all the stored data to the backend using the
Beacon API
Navigate to our analytics.js file in public/
->analytics.js
.
Inside our analytics.js file, the first thing we need to do is create an event handler that:
- captures the element we clicked on inside our document
- the time we clicked on it
- then push it to a global array that holds the history throughout the entire end users visit to the web page.
Let's do that!
First were capturing the element we clicked on and the time we clicked on it inside our document.
document.addEventListener('click', (event) => {
{
clickedElement: event.target.outerHTML,
timestamp: new Date()
};
})
Next we need to create a dataHistory
variable to store all data we capture from each click. Then push the captured data every time the user clicks inside the document.
let dataHistory = [];
document.addEventListener('click', (event) => {
dataHistory.push({
clickedElement: event.target.outerHTML,
timestamp: new Date()
});
})
Now we need create our analytics
function. This function will;
- execute on window.load and window.unload
- Check to see if our browser has the
navigator.sendBeacon()
method - If it doesn't it will simply return
- If it does we will define the url we are sending our analytics data to the backend
- Create a variable that will create a new
Blob
object that will hold our stringified JSON. - Send the data to the
/analytics
endpoint usingnavigator.sendBeacon()
What our analytics
methods should look like:
window.onload = window.onunload = function analytics(event) {
if (!navigator.sendBeacon) return;
// Url we are sending the data to
let url = "http://localhost:8081/analytics";
//Create the data to send
const dataHistoryBlob = new Blob([JSON.stringify(dataHistory)], { type: 'application/json' });
navigator.sendBeacon(url, dataHistoryBlob);
};
We've now completed our analytics.js file!
This is what our file should look like!
let dataHistory = [];
document.addEventListener('click', (event) => {
dataHistory.push({
clickedElement: event.target.outerHTML,
timestamp: new Date()
});
})
window.onload = window.onunload = function analytics(event) {
if (!navigator.sendBeacon) return;
// Url we are sending the data to
let url = "http://localhost:8081/analytics";
//Create the data to send
const dataHistoryBlob = new Blob([JSON.stringify(dataHistory)], { type: 'application/json' });
navigator.sendBeacon(url, dataHistoryBlob);
};
There's one last thing we haven't done. In our url variable we send the data to a backend endpoint we haven't defined yet, /analytics
. Let's go to our server.js file to create that endpoint and make sure it can parse the data it's receiving.
Creating The "/analytics" Endpoint
In our server.js file let's create the /analytics
endpoint.
const express = require("express");
const app = express();
app.post("/analytics", (req, res) => {
console.log(req.body);
res.sendStatus(204);
});
app.listen(8081, () => console.log("Listening on 8081"));
If we log the data won't be able to see anything due to express. All of our data is being passed through the body of our request. Unfortunately express itself can't parse data from the body so we have to use the body-parser
package from npm. Fortunately when we did an npm install setting up the project we already added the package as a dependency. Feel free to check your package.json for reference.
Now we need to add body parser to our server and use it to parse the json data being sent to the /analytics
endpoint. Our file should look like this.
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
//serving the static content inside our public folder
app.use(express.static('public'));
app.post("/analytics", (req, res) => {
console.log(req.body);
res.sendStatus(204);
});
app.listen(8081, () => console.log("Listening on 8081"))
If we save and restart our server we can click on several elements, refresh the page, exit the page, or navigate to a different website, we should see the data being sent and logged to our server. We have now successfully build a very simple use case for the beacon API!
Side note: To check to see what data is being sent to the backend on the browsers side. You can preserve the logs in the network tab.
Challenges:
Expand upon the project by:
- Separating the business logic(our click event) into our index.js file and have it import and use our analytics.js file.
- Expand upon the current tracking capabilities by adding unique sessions.
- Clean up the element retrieval data. We currently use
.outerHTML
see if there are better ways to find the elements we clicked on. :) - Create a pop up to give users the option to accept or decline tracking.
Happy coding!
Top comments (0)