Skip to contentSkip to navigationSkip to topbar
Looking for more inspiration?Visit the
(information)
You're in the right place! Segment documentation is now part of Twilio Docs. The content you are used to is still here—just in a new home with a refreshed look.

Collecting Pageviews on the Server Side


Segment believes that client-side collection is appropriate for collection of basic pageviews.

If you'd like to track page calls from your server to Segment, Segment recommends doing it in addition to any client side tracking you're doing with analytics.js, and doing it in a separate "source" so that you can configure where to send the (probably redundant, albeit higher-fidelity) data.

With this approach, you might use a request "middleware" to log a pageview with every page load from your server.

There are a few things to be mindful of if you want to make sure you can attribute these (anonymous) page views to the appropriate user in your client-side source (eg, for effectively joining these tables together to do down-funnel behavioral attribution). You'll want to ensure they share an anonymousId by respecting one if it's already there, and setting it yourself if not. To do that, you can read and modify the ajs_anonymous_id cookie value in the request.

Be sure to pass through as many fields as you can in Segment's Page and Common spec, so that you get full functionality in any downstream tools you choose to enable. Segment recommends specifically ensuring you pass the url, path, host, title, search, and referrer in the message properties and ip and user-agent in the message context .

Here's an example of an express middleware function that covers all those edge cases:

If you have any questions or would like help generally adopting this method for other languages and frameworks, be sure to get in touch(link takes you to an external page).

1
import express from 'express'
2
import Analytics from 'analytics-node'
3
import { stringify } from 'qs'
4
5
const app = express()
6
const analytics = new Analytics('write-key')
7
8
app.use((req, res, next) => {
9
const { search, cookies, url, path, ip, host } = req
10
11
// populate campaign object with any utm params
12
const campaign = {}
13
if (search.utm_content) campaign.content = search.utm_content
14
if (search.utm_campaign) campaign.name = search.utm_campaign
15
if (search.utm_medium) campaign.medium = search.utm_medium
16
if (search.utm_source) campaign.source = search.utm_source
17
if (search.utm_term) campaign.keyword = search.utm_term
18
19
// grab userId if present
20
let userId = null
21
if (cookies.ajs_user_id) userId = cookies.ajs_user_id
22
23
// if no anonymousId, send a randomly generated one
24
// otherwise grab existing to include in call to segment
25
let anonymousId
26
if (cookies.ajs_anonymous_id) {
27
anonymousId = cookies.ajs_anonymous_id
28
} else {
29
anonymousId = = uuid.v4()
30
res.cookie('ajs_anonymous_id', anonymousId )
31
}
32
33
const referrer = req.get('Referrer')
34
const userAgent = req.get('User-Agent')
35
36
const properties = {
37
search: stringify(query)
38
referrer,
39
path,
40
host,
41
url
42
/* ++ any custom props (eg. title) */
43
}
44
45
const context = {
46
campaign,
47
userAgent,
48
ip
49
}
50
51
// send a call to segment
52
analytics.page(
53
anonymousId, // either random (matching cookie) or from client
54
userId, // might be null
55
properties,
56
context
57
)
58
59
// proceed!
60
next()
61
})