Web Components for American Express
From late 2022 to early 2026, Batunet technically implemented and maintained interactive web components: a credit card comparison, a personal inflation calculator and a range of table, navigation and promotional modules. The development took place as part of a project chain for the German-language guide section of American Express; American Express was not Batunet’s direct contracting party. As the number of components grew, so did the maintenance effort — which led to a Symfony application that manages product information and content centrally and delivers the components as JavaScript.
The case in one minute.
- Context
- Pages in the German-language guide section of American Express. The development took place as part of a project chain; American Express was not Batunet’s direct contracting party.
- Role
- Technical implementation and multi-year maintenance of the components; development of the application for central management and delivery.
- Timeframe
- December 7, 2022 to March 17, 2026, documented by the version history.
- Components
- Credit card comparison, head-to-head comparison of two cards, personal inflation calculator, comparison table, mobile sticky navigation, sticky bar with detail view, promotional modules.
- Comparison logic
- User-set weights across several criteria, a score per card, normalization to a percentage against the top-ranked card, filtering, a defined order when nothing is weighted.
- Central management
- Data model of product records and component-specific field values, declarative field sets for around twenty component types, an editorial interface with login and role restrictions, preview before delivery.
- Delivery
- Server-rendered JavaScript; the target page includes a script and provides a container.
- Technical environment
- First generation HTML, CSS and JavaScript; second generation PHP and Symfony 7.1 with Doctrine, Twig and EasyAdmin.
- Scope note
- Product content, terms, images and brand assets did not come from Batunet. Libraries for charts, carousel and input masks are third-party code. The version history also contains a contribution from another project participant.
Building blocks for pages that belong to others.
The American Express guide section explains card products and financial topics in editorial pages. These pages were to include tools that can do more than text: compare, calculate, present products clearly. The pages themselves, their structure and their operation were not our responsibility.
This leads to the basic condition of this case. A component runs in a document that doesn’t belong to it, on devices whose width it doesn’t know. Each component therefore brings its own markup, styling and data. Whatever it still expects from the target page — a specific library, for example — is explicitly stated as a prerequisite instead of being silently assumed.
Batunet was responsible for the technical implementation and maintenance, working within a project chain; Batunet was not a contracting party of American Express. Content, terms and brand assets did not come from us.
Decision aids that calculate.
Two of the tools answer questions that every reader asks differently. Which card fits what matters to me? And how hard does rising inflation hit me if my shopping basket isn’t average? Both answers are produced in the browser, instantly and without logging in.
In addition, there were components without their own calculation logic: a comparison table, a mobile product navigation, a bar fixed to the bottom of the screen with a detail view, and static promotional modules with product image, benefits and application link. Their challenge was less the logic than the presentation on every device.
What they all had in common was that they weren’t finished after the first delivery. Links, terms, images and copy changed constantly — and this part of the task later shaped the case more than any single component.
The ranking belongs to the user.
A comparison with a fixed order answers the provider’s question. Here, the weighting is up to the reader: for several criteria, they set in three levels how important each one is to them. From this, a score is calculated per card from weight and attribute value. Two criteria carry a fixed balancing factor so that they don’t dominate the result through their magnitude alone.
The score itself means nothing to anyone. What is displayed, therefore, is a percentage against the top-ranked card. If nothing is weighted, a fixed default order applies instead of a random one. A filter separates matching from non-matching cards without hiding the latter — they appear set apart below the results.
On wide screens, the cards sit side by side and open a detail view. On narrow screens, the list becomes a carousel, and the application link follows the card currently in the center.
In 2025, a second tool was added: a head-to-head comparison of two freely chosen cards across eleven categories, from fees to travel and insurance benefits.
- Input
- Weighting per criterion, Filter, Reset to the default state
- Calculation
- Score from weight and attribute value, Fixed balancing factors, Normalization against the top-ranked card
- Result
- Sorted list with percentage, Non-matches set apart, Detail view per card
- Presentation
- Card grid on wide screens, Carousel on narrow viewports, Application link follows the centered card
The same index, a different basket.
The official inflation rate describes an average household. Someone who drives little and heats a lot experiences a different rate — not because the number is wrong, but because it is weighted by someone else’s basket of goods.
The inflation calculator therefore takes the official index series — the overall index and nineteen spending categories — and weights them by the expenses a person enters themselves. For each month, a personal index value is calculated as a weighted average; the annual rate results from comparison with the value twelve months earlier. A chart shows the personal and official trends side by side, optionally with a single category as well.
The real effort lies around the formula. Amounts are entered the way people think about money: in euros, without decimals. For each category, the calculator shows a reference value from a standard weighting, based on the stated total expenses. Unassigned expenses go into a separate remainder category, and the result is recalculated with every input. If the categories exceed total expenses, the calculator shows a notice instead of a number that can’t exist.
Little logic, many devices.
The remaining components don’t calculate. A comparison table sets several cards against each other row by row and gets its own layout on narrow screens instead of a scaled-down version. A mobile product navigation expands from the edge of the screen. A bar fixed to the bottom opens an overview with a detail view that closes again on click, via the backdrop or with Escape, and runs as a carousel on narrow screens.
The first-generation promotional modules were static HTML and CSS in three variants — as a list, as a compact menu and as a card grid. Technically, these components are simple. Their cost arose elsewhere: the same product information appeared in several modules, each in its own repository with its own history.
What ages in embedded components.
Throughout 2023 and 2024, a large part of the work consisted of changes that had little to do with code: new link targets, changed welcome credits, replaced images, renamed products. Each of them had to be applied in several separate components, sometimes in variants of the same tool that were maintained in parallel.
As long as there are only a few components, this goes unnoticed. With each additional one, the same piece of information sits in one more place. The point at which this tips isn’t a technical error but a question of volume.
Files become data.
The answer wasn’t another component, but a layer beneath: an application based on Symfony 7.1 in which product information and component content are stored as data rather than source code.
The model is kept small. A product record carries the information needed everywhere — name, image, links. Each component has named field values. Which fields a component type knows is defined in a declarative configuration, most recently for around twenty types. A new type thus remains a configuration question and doesn’t become a model change.
Field values can reference product information; at render time, these references are resolved from the product record. A changed piece of information therefore takes effect in every component that uses it, instead of having to be updated file by file.
Delivery is server-rendered: a component’s template is combined with its data into JavaScript that the target page includes. Before that comes a preview that shows the same component at different screen widths. Content is maintained in an editorial interface with login and role restrictions.
The transition happened in stages. At first, content was imported via CSV file; later it was maintained in a data model with an editorial interface. Existing components, including the credit card comparison, were moved into the application — their calculation logic stayed the same, and their data has come from the server ever since.

- 01
Product data
One record per product carries the information that all components share.
- 02
Field set
For each component type, the fields it knows are defined declaratively.
- 03
Editing
The values are maintained in a role-restricted interface, not in source code.
- 04
Merging
At render time, references to product information are resolved from the record.
- 05
Preview
The component is checked at several screen widths before delivery.
- 06
Delivery
The same component is output as JavaScript and included by the target page.
Three years, two generations.
The work didn’t run as a project with a start and a sign-off, but as continuous development. The version history runs from December 7, 2022 to March 17, 2026 and shows two generations: first standalone embeddable components, then a central application into which existing components were moved.
- 01
Late 2022 to early 2023
Inflation calculator with calculation, chart and input form.
- 02
Spring 2023
Credit card comparison, comparison table and sticky components.
- 03
Mid-2023 to late 2024
Ongoing maintenance, static promotional modules, variants maintained in parallel.
- 04
Late 2024 to mid-2025
Foundation of the Symfony application, CSV import, migration of the comparison.
- 05
Mid to late 2025
Data model with editorial interface, head-to-head comparison, new component types, migration of further modules.
- 06
Late 2025 to March 2026
Switching delivery to the new data model and further maintenance.
What was ours — and what wasn’t.
Batunet was responsible for the technical implementation of the components, their maintenance over more than three years and the development of the application for management and delivery.
Not our responsibility were the pages in which the components were embedded, their operation, and product content, terms, images and brand assets. Chart, carousel and input libraries are third-party code, and the version history also contains a contribution from another project participant.
- With Batunet
- Implementation of the components, Calculation and comparison logic, Responsive presentation, Maintenance over several years, Data model, editorial interface and delivery
- Not with Batunet
- Target pages and their operation, Product content and terms, Images and brand assets, Contractual relationship with American Express
The right time for a dedicated layer.
In hindsight, the interesting part isn’t any single component but the transition. For a handful of modules, a dedicated management application would have been overkill: it costs operations, maintenance and onboarding before it saves anything. With several components that carry the same product information and change constantly, the equation tips.
The migration was gradual, component by component, over several months. That was possible because the components already existed separately. The comparison’s calculation logic, for example, remained unchanged during the move; what was replaced was the source of the data.
Technologies used
Two generations in one case: standalone frontend components in HTML, CSS and JavaScript with no framework dependency, later a Symfony application for management and delivery. jQuery, Owl Carousel, Highcharts and Inputmask are third-party libraries and are listed as such.
Where this case connects.
Questions about this case
Was American Express a client of Batunet?
No. The development took place as part of a project chain for the German-language guide section of American Express; American Express was not Batunet’s direct contracting party. Batunet was responsible for the technical implementation and maintenance of the components. Product content, terms and brand assets did not come from us.
How does a product comparison with weighted scoring work?
The weighting is up to the user. For several criteria, they set how important each one is; this produces a score per product, which is normalized to a percentage against the top-ranked product. Criteria with a different order of magnitude need a fixed balancing factor; otherwise one of them alone determines the result.
How do you calculate a personal inflation rate?
You take the official index series for the individual spending categories and weight them by your own expenses instead of the average basket of goods. For each month, this yields a weighted index value; the annual rate is the comparison with the value twelve months earlier.
When is central management worthwhile for embedded components?
As soon as the same content change has to be made in several places. For one or two components, a dedicated application is overkill. If several components carry the same product information and it changes constantly, a data layer with an editorial interface is cheaper than updating every single file.
How is a component embedded in a third-party page?
Via a script and a container element. The script brings the component’s styling, behavior and data and renders into the container. In the second generation, this script is generated server-side from the template and the data.
Related topics.
Guides, decisions, services and case studies connected to this page.
Let’s talk about your project.
Tell us briefly about your project. Your first conversation is directly with our management.
