I was unsure if I should add an analytics solution to my website in the first place. I am unfamiliar with Google Analytics and similar tools, and disliked that I needed to add a cookie banner. On the other hand I wanted to know how much people read which blog post, and download my cv, so I looked if I can integrate something AWS native. I came across AWS RUM (Real User Monitoring) as a solution for what I wanted to achieve. While AWS RUM is designed for debugging performance and errors rather than usage analytics, it can be tailored to my needs with little effort.
Advantages of AWS CloudWatch RUM
- Platform consolidation - Keeping all monitoring, logging, and infrastructure in AWS simplifies operations
- Infrastructure as Code (IaC) - Full CDK support for automated deployment
- Seamless integration - Native connections to other AWS services like CloudWatch Dashboards and Alarms
NOTE On the other hand Google Analytics and other usage tracking tools provide way better metrics out of the box and might be a better fit for tracking than RUM. The main reason I chose RUM was to explore this AWS Feature, I am totally aware that it is not the best choice for usage analytics.
Implementation
Infrastructure
I have my infrastructure as AWS CDK Code, but you can map it to any IaC if required. We need a so called AppMonitor in AWS CloudWatch RUM, and some IAM Resources to allow anonymous website users to push events. You create an IdentityPool, and specify that unauthenticated users (AWS Documentation for Roles) have the permissions to the action rum:PutRumEvents
, this way anonymous users can request credentials from the Cognito IdentityPool. Another option would be to create a user with the permissions and just hard code the access key. But temporary credentials are always preferred.
You can take a look at the code:
// Create IdentityPool
const identityPool = new cognito.CfnIdentityPool(this, 'RumIdentityPool', {
allowUnauthenticatedIdentities: true,
identityPoolName: `${this.node.id.toLowerCase()}-identitypool`,
});
// Create Role that can be assumed by unauthenticated cognito users
const rumUnauthRole = new iam.Role(this, 'RumUnauthRole', {
assumedBy: new iam.FederatedPrincipal(
'cognito-identity.amazonaws.com',
{
StringEquals: {
'cognito-identity.amazonaws.com:aud': identityPool.ref
},
'ForAnyValue:StringLike': {
'cognito-identity.amazonaws.com:amr': 'unauthenticated'
}
},
'sts:AssumeRoleWithWebIdentity'
),
description: 'IAM role for CloudWatch RUM unauthenticated users',
});
// Grant permissions for the rum action to the role
rumUnauthRole.addToPolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
'rum:PutRumEvents'
],
resources: [`arn:aws:rum:${this.region}:${this.account}:appmonitor/${this.rumAppMonitor.name}`],
}));
// Add the role for unauthenticated users in the identity pool
new cognito.CfnIdentityPoolRoleAttachment(this, 'IdentityPoolRoleAttachment', {
identityPoolId: identityPool.ref,
roles: {
unauthenticated: rumUnauthRole.roleArn,
},
});
this.rumAppMonitor = new rum.CfnAppMonitor(this, 'WebsiteRumMonitor', {
domain: props.domainName,
name: 'website-monitor',
customEvents: { status: "ENABLED" },
appMonitorConfiguration: {
allowCookies: true,
enableXRay: false,
sessionSampleRate: 1,
telemetries: ['errors', 'performance', 'http'],
identityPoolId: identityPool.ref
},
cwLogEnabled: true
});
This sets up the required infrastructure for the AppMonitor so that we can record events.
Application
To integrate this solution into your website you need to add the aws-rum-web
npm package, and initialize the client. AWS provides a download button for the configuration for starters, later I replaced it with a automatic approach (to export the values from IaC and import them into the application on deployment).

You can copy your configuration from the aws console for a initial test. To fit my requirements I added two more functions for the custom events I want to send:
export function recordCustomEvent(eventType: string, eventData?: Record<string, unknown>): void {
if (!awsRumInstance) {
return;
}
try {
awsRumInstance.recordEvent(eventType, eventData || {});
} catch (error) {
console.error(error)
}
}
export function recordCvDownload(format: string): void {
recordCustomEvent('CVDownload', { format });
}
export function recordBlogRead(title: string): void {
recordCustomEvent('BlogRead', { title });
}
Now I can process these events using a AWS Dashboards and a Log Insight Query:
SOURCE logGroups(namePrefix: ["/aws/vendedlogs"], class: "STANDARD") |
fields @timestamp, event_type, event_details.pageId, user_details.sessionId
| filter event_type = "BlogRead"
| stats count_distinct(user_details.sessionId) as reads by event_details.title
And get an idea of how many people read >80% of which blog post. This is how the dashboard looks like:

Conclusion
While AWS CloudWatch RUM isn't the most conventional choice for website analytics, it proved to be an effective solution for my specific needs. The integration with existing AWS infrastructure eliminates the need for additional third-party services, and the custom event tracking provides the insights I was looking for.
Key takeaways:
- RUM works well for basic usage tracking when you're already in the AWS ecosystem
- The setup requires more configuration than traditional analytics tools
- For comprehensive analytics, dedicated tools like Google Analytics remain superior
- The approach is particularly valuable when you need custom event tracking alongside performance monitoring
If you're already using AWS and want to avoid external analytics dependencies, CloudWatch RUM can be a viable alternative for tracking user engagement on your website.