Case Study - Tracking ARPU with Adjust

Concrete Software's Integration with Adjust to Track ARPU by User Acquisition Source

Concrete Software uses Adjust - a mobile app attribution platform, to track performance of its user acquisition sources. The Cloud Services team implemented an integration with Adjust to track user revenue and determine Average Revenue Per User (ARPU) for each user acquisition source.

This allows Concrete Software to determine appropriate spending levels for each user acquisition source.

Problem Statement

Tracking ARPU by User Acquisition Source

Concrete Software advertises its Android and iOS games through user acquisition channels such as Facebook and Google, often running multiple campaigns on each channel. From these advertisements, Concrete Software acquires users, who can generate revenue within the games through in app purchases and in-game advertising.

We needed a way to determine the quality of users being acquired from advertisements - specifically to determine how much revenue they are generating. If the average revenue per acquired user is greater than the amount being spent, Concrete Software could increase spending on the advertisement, which increases revenue and helps to increase the app’s rankings in the app stores.

Adjust provided the ability to record revenue from in-game events, but that method doesn’t work well for in-game advertisements, because we aren’t able to determine the amount of revenue from advertising events until days later when we receive revenue reports from the ad networks.

Because of this, we implemented a server-to-server (S2S) integration with Adjust to provide advertising revenue from Concrete Software’s App Sales Tracking System.

Solution Architecture

Server-to-Server Integration to Report Revenue to Adjust

Concrete Software's cloud services team designed and implemented an integration with Adjust, illustrated at a high level in the following diagram.

With this implementation, Adjust and Concrete Software hold the needed revenue data to compute the ARPU for users acquired from advertising, and we are able to use Adjust’s dashboard and Concrete Software’s reporting tools to view the metrics.

Concrete Software implemented a Microservice for interacting with Adjust, which includes two stateless AWS Lambda functions. We chose AWS Lambda for a few reasons:

  • Easy to Manage - It allows us to provision code to run, without needing to provision or manage servers.
  • Continuous Scaling - Several instances of lambda functions can execute concurrently.
  • Cost Effective - We only pay for the compute time we use.

We implemented the following Lambda functions:


The processEventsFromAdjust function is periodically called by a CloudWatch event rule to process event data sent by Adjust.

It saves event data to Concrete Software’s Redshift database, where it can be used for analysis and revenue processing.


The sendRevenueEventsToAdjust function is periodically called by a CloudWatch event rule. It reads revenue-affecting event data saved by processEventsFromAdjust and uses Ad eCPM Data from the App Sales Tracking System to form revenue events, which are sent to Adjust.

The function processes events that are at least 7 days old (since the date the user triggered the event), to ensure the revenue data is accurate within the App Sales Tracking System.

Design Issues Addressed

The following issues were addressed while designing the service.

  • Revenue Event Time Ordering - Adjust requires revenue data for each user be sent in order by time. If the service only provided revenue for ads, with the game providing revenue for in-app purchases, that time ordering would have been broken.
    • Resolution: No revenue was provided directly from in-game events, and all revenue data is sent from Concrete Software’s service, including ads and in-app purchases. This required a couple issues to be addressed:
      • Synchronization - We needed careful synchronization of revenue sending to ensure proper order. This was implemented via the DynamoDB status table.
      • Scaling - Adjust’s API calls are time-consuming, so it was important for us to have the ability to scale the sendRevenueEventsToAdjust processing horizontally and keep up with incoming event data. We implemented a scheme to hash the user IDs to determine which events a particular instance of the function would process; this allows multiple calls to the function to be executed concurrently while still ensuring proper event ordering.
  • Event Mapping - Event data from Adjust came into the system using Adjust-specific event identifiers. We needed a way to determine which database tables events should be saved to, and to determine which events affected revenue.
    • Resolution: We implemented JSON configuration files (stored within an S3 bucket) to map events to the Redshift database.
  • Adjust API Errors - A few of the Adjust APIs would periodically return errors, which we needed to know how to address.
    • Resolution:
      • - We implemented an easy ability to search through CloudWatch logs for the details needed to report failures to Adjust’s customer support.
      • - We implemented a tool to track revenue processing events back to the original event data sent by Adjust, so we could report these additional details to Adjust’s customer support.
  • Service Monitoring - We needed to ensure Concrete Software’s service stays running and isn’t stalled by critical failures.
    • Resolution: The service is monitored for errors through CloudWatch error and log filtering alerts. We also implemented AWS Lambda functions to watch for frequent errors, unprocessed Adjust event files, and revenue processing falling too far behind.
  • AWS/Adjust Reliability - Sometimes errors occur using the AWS services and Adjust, caused by network connectivity issues to the database, S3, and Adjust’s event API. These are intermittent errors that should not stop the service from processing events or require notification unless if they continue to fail.
    • Resolution: We implemented logic to automatically retry upon failure. If a service fails after several retries, an alert is triggered and a system administrator is notified. With this logic, alerts for these types of errors are very rare.

Project Outcomes

All solutions were implemented and work well
  • Concrete Software’s advertising managers are able to get a reliable ARPU for specific ads using custom Tableau and Google Sheets reports that reference Concrete Software’s database. They are able to increase/decrease spending based on each ad’s performance, increasing overall game revenue.
  • Event and revenue processing runs smoothly, with minimal system maintenance required. System administrators are notified when there are major system errors.
  • Errors from the Adjust API are easily able be reported to Adjusts support team.

TCO Analysis Performed

  • The services were implemented using Lambda functions, so Concrete Software only pays for what it uses. We’ve monitored the Lambda costs, and so far they have been very low.
  • The other main costs are the DynamoDB read/write capacity and Redshift database. We use AWS reservations for both to help reduce costs.

Find out More

Contact us to find out more about this case study and our cloud services team.

You can also email us directly at