Scaling Campaigns at Spotify: From Monolith to Distributed Tooling

Historically, Spotify ran a single major holiday campaign each year across platforms like the Spotify Homepage and the Premium page. Over time, the goal shifted: instead of one centralized team configuring campaigns across markets, the company wanted local teams able to tailor campaigns for their specific audiences throughout the year — including holidays like Halloween or Easter.

From PHP Monolith to a Growing Need for Flexibility

In its earlier form, the Spotify website was a PHP monolith. As more teams contributed to it, coordination became a bottleneck: pull requests frequently blocked each other, and the Docker image for building the site took more than 30 minutes on developer machines — with build times only getting worse as the engineering team grew.

Year-end campaigns compounded the problem. Each page was built entirely from scratch across multiple markets, requiring distinct translations, imagery, and regional nuances. A single end-of-year campaign could consume up to three months of preparation. As Spotify expanded into new markets, managing one annual campaign became a full-time workload.

The Rise and Fall of Campaign Admin

During a hack week, the team built a tool called Campaign Admin. It allowed developers to upload imagery to a GCS bucket, configure strings in web and in-app pages, and request translations per market. This sped up simple campaigns considerably, letting an in-house team handle many setup tasks while engineers focused on site performance and tooling.

But efficiency created its own problems: the more capable the tool became, the more scope crept in. By the end, internal users could modify components, colors, text, CSS, and snippets of HTML directly within the tool. That flexibility made the interface nearly unworkable for marketing users and made it increasingly easy to break the site. The team recognized the real audience was no longer developers, but internal marketing users. What was needed was a better user experience with built-in guardrails — and support for a new generation of campaigns. The result was the Spotify Toolbelt.

The Spotify Toolbelt and the Marketing Vertical

An ongoing effort to break up the monolith had produced “verticals” — focused segments of the website, each owned by a single team. The marketing pages were among the first verticals split out from the original monolith. This vertical ran as a Node.js Express app that server-side rendered an in-house library of landing page React components.

Example of the routing layer with each vertical owned by separate teams.

Blueprints and Targeting

The first piece of the Toolbelt was the Scheduler-API, which served as the data source for the marketing vertical. The team incorporated lessons from Campaign Admin into its design, prioritizing key features: editing any component on web or in-app pages, and avoiding duplicate content configuration for every market.

That led to the concept of blueprints. A blueprint defines a page and can be expanded into different markets. Example blueprints include modules for translations; these modules contain placeholders, such as pricing for offers shown to end users.

Example of the JSON blueprint with modules to be expanded.

The translation module was the most common blueprint module. It embeds strings into a blueprint, and at runtime the correct translation is matched for the appropriate market via Spotify's translation system. Strings can also have dynamic data inserted — user names, offer details, and similar values.

Alongside blueprints, the team designed a targeting system to determine which external users see which pages. A decision tree evaluates multiple factors — for example, the user’s market, offer eligibility, device type, or even their current favorite artist — and selects the best blueprint to serve.

Example of the decision tree serving different content to the right user.

Creating a Better Editor Experience

The Campaign Admin experience of free-text boxes requiring users to type variable names manually was not scalable. But building distinct user experiences for each surface was equally impractical. The solution: a reusable React editor component that accepts a JSON schema and generates a blueprint for the Scheduler-API.

Example of the editing experience for the Premium page.

Anyone integrating with the Scheduler-API only needs to write a JSON schema defining their desired data shape — and a unique editor experience follows. For the example blueprint from earlier, the schema looks like this:

{
  "simpleField": { "type": "string" },
  "moduleField": { "type": "translation" }
}

Fairly complex fields can be expressed by extending this simple schema. Every component on Spotify’s web pages, plus several in-app pages, is now described through schemas like this one.

Teams iterate on their schemas independently. One integrating team, for instance, generates TypeScript types directly from its schema, eliminating the inconsistent variables that sometimes surfaced in the past.

With the editor, internal users work WYSIWYG — configuring components, strings, imagery, and colors without exposing the underlying fragility of the old system. Once content is complete, it can be submitted for translation; the tooling calls the relevant APIs and notifies users when translations are ready. Pages go live only after an approval process.

What’s Next for Campaign Development

The configuration effort has shifted in kind: larger campaigns now take vastly less time to set up, even as market count and targeting complexity rise. Spotify has grown its campaign volume and, at the same time, handed day-to-day operational control to local marketing teams. That outcome aligns with the initiative’s core aims — yet work continues on making the tooling more accessible and preparing for the next wave of campaigns.