Website Monitoring with AWS CloudWatch RUM

May 2025

Hero image for Website Monitoring with AWS CloudWatch RUM

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

  1. Platform consolidation - Keeping all monitoring, logging, and infrastructure in AWS simplifies operations
  2. Infrastructure as Code (IaC) - Full CDK support for automated deployment
  3. 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).

AWS RUM configuration export

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:

AWS RUM configuration export

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.