Dynamic pricing

All we got wrong on dynamic pricing for EV chargers

Three years of calculating on pricing for AC and DC chargers. The model that follows the energy price turns out to earn less than a flat rate on most chargers. All five models worked through, with charts.

Curious what these models would do on your own charger? The free potential analysis runs the same model on your numbers. Start the analysis ± 3 minutes · PDF in your inbox · every assumption stated

I have spent a little over three years on the same question: what is the right price for a kilowatt-hour at an EV charger? Not the highest one. The right one. A price the charger owner earns decently from, without the driver who pulls in at seven in the evening on 8% battery being the one who pays for it.

In that time I have built price curves, run backtests on real charging sessions, ingested day-ahead prices and eventually put a pricing model into production on chargers that make or lose money every day. What I take away from it is more uncomfortable than I expected. The model most commonly sold as "dynamic pricing", where your selling price follows the energy exchange, does not do what operators think it does. It is not badly built. It simply optimises something other than profit.

That model is intuitive and easy to explain to a customer, which probably explains why it persists. But on most chargers I have run the numbers for, it earns less than a boring flat rate. Below I work through every pricing model you can switch on in Proxilink, with a chart for each, and end at the one we built ourselves.

The assumption everyone inherits

The reasoning behind energy-led pricing is simple. Your purchase cost varies every quarter-hour, so your selling price varies with it. Expensive hour, expensive price. Cheap hour, cheap price. Your margin stays constant and you are transparent about it.

That reasoning protects your margin per kilowatt-hour. The trouble is that a charger does not earn margin per kilowatt-hour, it earns margin times volume. Volume does not depend on what the power exchange is doing. It depends on how many cars are parked at your site in that hour, and on how sensitive those drivers are to your price. As long as that second factor is missing from your model, you are optimising one part of the equation and leaving the rest to chance.

Why the energy price is not the same thing as demand

Take a charger at a leisure destination. A bowling alley, a sports club, a retail park. Occupancy peaks between one and six in the afternoon. On a sunny Belgian day that is the window in which the day-ahead price dives into the solar trough, sometimes as low as 20 or 30 euros per MWh.

What an energy-led model does there is put your lowest price of the day on your busiest hour. You hand a discount to people who were coming anyway. At night, when spot prices climb again and nobody is charging, your price goes up, while a discount in those hours might well have won you extra volume.

This is not a rare scenario. It is the standard profile of just about every destination charger where people charge while doing something else, and it explains why three of the five models below end up below a flat rate on such a charger.

The four models without AI

Proxilink lets you choose between four classic strategies. None of the four is bad. They each solve a different problem, and that problem is not necessarily yours.

Every chart below shows the same day, the same charger and the same starting point: a flat rate of 0.45 euro per kWh (the dashed line), a purchase cost of spot plus a 0.05 euro add-on, and the demand profile of a real destination charger with an afternoon peak (the shaded bars). The profit percentages are estimates on that one profile. They shift completely as soon as your demand profile shifts, which is the whole subject of this article.

1. Flat + spot

The simplest model. Your price this quarter-hour is your base price plus the difference between the purchase cost right now and today's average purchase cost. If spot sits above the daily average, so do you. Below it, and you sit below. One to one, without amplification or damping.

0,350,450,550,65€0,4500u04u08u12u16u20u23u

Flat + spot tracks the spot price one to one. Price range 0.39 to 0.52 euro. Estimated profit difference against the flat rate on this demand profile: around −4%.

This works for operators on a variable energy contract whose main concern is never selling below cost on an expensive day. A sign reading "our price follows the energy exchange" is a story customers understand, and that explainability is worth something in itself.

What you give up: your selling price moves every quarter-hour, including mid-session, and it steers no behaviour at all. If your demand peak sits in the solar trough, you systematically discount your best hours.

2. Forward locked

The same idea, but looking ahead. Instead of the spot price right now, the model takes the expected purchase cost across the whole session. Proxilink knows the average session duration per part of the day on your charger, looks ahead across that window in the day-ahead curve, and prices on that average. The price is locked at session start, so what the customer sees when scanning is what they pay.

0,350,450,550,65€0,4500u04u08u12u16u20u23u

Forward locked prices on the expected purchase cost across the session, locked at start. Price range 0.39 to 0.51 euro. Estimated profit difference: around −3%.

Of the five models this carries the least risk. Your margin per kWh stays protected even when a session runs across a price step, and there is no bet on customer behaviour anywhere in it. For fast chargers along transit routes, where drivers stop because they have to rather than because you are cheap, this is the model I would switch on without further analysis. It is purely defensive: it protects what you have and goes looking for nothing.

3. Spot two-way

Forward locked with an amplifier on top. The deviation from the daily average is multiplied by (1 + aggressiveness), so you go further up on expensive hours and further down on cheap ones. The intent is to steer behaviour, shifting charging into the cheap hours.

0,350,450,550,65€0,4500u04u08u12u16u20u23u

Spot two-way amplifies the spot deviation (aggressiveness 0.35). Price range 0.37 to 0.53 euro. Estimated profit difference: around −4%.

That works on chargers where the user genuinely can move their charging moment and where that shift saves you money: a residential car park, an apartment building, a company fleet parked overnight. There, a deep night discount really does move volume into cheap hours.

Passers-by cannot shift anything, and then the amplification works the wrong way. You dip deeper on the hours where you were selling anyway and push yourself higher on hours when nobody turns up. Of the five models this one does the most damage when applied to the wrong type of charger.

4. Demand seek

Here we drop the energy price as the steering variable and price on occupancy instead: more expensive during busy hours, cheaper during quiet ones. The energy price does not disappear from the model, but falls back to the role of a floor.

Two safeguards keep it safe. The neutral point is the volume-weighted average of your demand, so with unchanged behaviour your average price lands on your base price rather than below it. Underneath sits a day-ahead floor of purchase cost plus a minimum margin, so a quiet-hour discount can never dip below your cost, not even on an expensive winter day.

0,350,450,550,65€0,4500u04u08u12u16u20u23u

Demand seek prices on occupancy (shaded bars), with a day-ahead floor. Price range 0.39 to 0.49 euro. Estimated profit difference: around +3%.

For chargers with a clear, repeating occupancy pattern this is a sensible choice: destination chargers, hospitality, retail. In our backtest on a charger in Diest this was the first model to come out above the flat rate while the spot models stayed below it.

There is a catch. On a charger whose demand sits in the cheap overnight trough, a hotel or a residential car park for instance, this same model drops to −8% in our calculations. It puts a surcharge on the night hours, which are exactly the hours when purchasing is cheap and the customer is most price-sensitive. Pricing on demand without knowing how price-sensitive that demand is remains half the job.

What we got wrong

That half job is the mistake I carried for three years. We treat pricing as a cost problem when it is really about behaviour.

Purchase cost sets your floor and nothing else. Your optimum sits where one extra cent on your price earns as much as it costs you in lost volume, and where that point lies depends on something quoted on no exchange anywhere: the price elasticity of your customers, on your charger, in that hour.

At five in the afternoon at a retail park, with a half-empty battery and a car parked there anyway, that elasticity is low. People charge at a higher price too. At three in the morning, when a driver sees three alternatives in a routing app, it is high. Same charger, same cost, different optimum. A spot-driven model cannot possibly see that difference, because the information is not in the spot price.

The fifth model: hourly profit optimum

Our own model, known internally as ai_elastic, therefore starts from the optimum rather than from cost. For every quarter-hour it computes where profit peaks, given an estimated elasticity e for that hour:

p* = base price × (1 + e) / (2e) + purchase cost / 2

That is the profit optimum of a linear demand model anchored on your own base price. The logic reads directly. If e sits below 1, your audience is not very price-sensitive and the optimum sits above your base price; not taking it leaves money on the table. If e sits above 1, the optimum sits below, but only when the discount pays for itself through extra volume. Mathematically that happens only when your purchase cost sits below base × (e−1)/e. A discount that does not pay for itself simply is not given.

Three layers on top make the model usable.

  • Aggressiveness as a fraction. A slider between 0.1 and 1.0 sets how far towards the computed optimum you go: p = base + aggressiveness × (p* − base). At 0.2 you stay close to your familiar rate, at 1.0 you go all in.
  • Demand tilt. On top of the elasticity optimum comes a correction for occupancy, using the same volume-weighted anchor as demand seek. More expensive during the busiest hours, and below your base price during quiet ones to attract extra customers.
  • Hard limits. A day-ahead floor of purchase cost plus minimum margin, along with your own minimum and maximum price, clamp every computed price. Whatever you set, the model cannot dip below your cost or exceed your ceiling.
0,350,450,550,65€0,4500u04u08u12u16u20u23u

AI profit optimum per hour, bounded by a 0.32 euro floor and a 0.62 euro ceiling. Cheaper than the flat rate at night and in the early morning, more expensive during the inelastic afternoon peak. Estimated profit difference: +10% to +21%, depending on how price-sensitive customers actually turn out to be.

Look at where that curve runs at night and in the morning. For 15 of the 24 hours the price sits below the flat rate. The model is not simply extracting more; it puts the price where it belongs in each hour, and for more than half the day that means cheaper.

Why this needs AI

Everything above hangs on that single parameter e, and elasticity cannot be read off anywhere. It has to be estimated, per charger and per hour, from behaviour. That calls for something that learns rather than calculates.

  • Three-stage estimation. First a charger's own regression, log volume against log price, per hour, across all observed days. Too few points or too little price spread, and the model falls back to a network-wide estimate across all connected chargers. If that is missing too, conservative priors per part of day apply: elastic at night (1.8), inelastic during the evening peak (0.5).
  • Shrinkage on sessions. A charger's own estimate is weighted by the number of sessions behind it, through w = sessions / (sessions + 80). An hour with five sessions leans heavily on the network and the prior; an hour with four hundred trusts itself. One odd week cannot upend your prices.
  • Clamping before blending. Raw regressions on real charging data sometimes produce nonsense. We have seen fits suggesting that higher prices bring more volume. Every raw estimate is therefore clamped to the interval 0.2 to 3.0 before being blended with the prior. That detail seemed small until we saw it in production: without that ordering the morning estimate stayed pinned to its lower bound and the curve stopped following occupancy.
  • Data from roaming. The training data does not come from your own QR sessions alone. On one of our chargers, 82% of the kilowatt-hours delivered are roaming, from drivers on a dozen different e-MSPs each paying a different price. Those differences between providers deliver the price spread an elasticity estimate needs. Without access to those CDRs, every estimate stays pinned to its prior.

The estimate is recomputed weekly. The price curve is generated daily at two in the afternoon, as soon as day-ahead prices are known, and the price a customer pays is fixed from the moment their session starts. Nobody watches their price change while they are charging.

What it returns, and what we do not promise

On the chargers where this runs today, the model estimates its own profit effect at +5% to +17% against the flat rate that preceded it. That estimate uses the occupancy data it collected itself, and computes customers as both more and less price-sensitive than estimated to arrive at that band.

Then the point I started from three years ago: return must not come from the customer's ignorance. That is why the floor and ceiling are hard, why the full daily curve is fixed in advance and publishable, why the price is fixed at session start, and why the model dips below your base price in the hours when the customer is price-sensitive. A driver charging with you at night pays less than under a flat rate. That discount is not a concession on returns; part of the return comes precisely from it, because it brings volume you would not otherwise have had.

Stack revenue models on top of the dynamic rate

A dynamic rate is a pricing engine and nothing more. The return only comes loose when you put several revenue streams on top of it, each serving a different type of customer. In Proxilink they run side by side on the same charger.

  • Ad-hoc via QR. A passer-by scans, pays by card and charges, with no app, no registration and no e-MSP commission on your margin. On this channel your dynamic price keeps its full value, because nobody sits in between.
  • Memberships. A monthly fee plus a discount per kWh. That discount comes on top of the dynamic price, so your regulars follow the same curve but well below it. Memberships cover part of your fixed costs before the month's first session, and they make your most price-sensitive group loyal straight away.
  • Reservations. In the hours where your model applies a surcharge because it is busy, you can sell that same scarcity directly through a reservation fee up front, on top of the charging session. The two reinforce each other, since both convert the value of a busy hour into money.
  • Parking and time tariffs. An occupied charge point with a full battery earns nothing. A per-minute parking tariff after a grace period turns rotation into a revenue line, and those tariffs are pushed to the CPO platform as well so they apply to roaming sessions.
  • Fleet contracts. Company cars and fixed fleets on their own rate with monthly invoicing per card or per vehicle. Predictable volume that fills your occupancy trough, which is exactly where your model gives a discount.
  • Roaming. Visibility in the large charging apps delivers the volume everything else runs on, and as noted above, those sessions are simultaneously your best training data.

Each stream has its own pricing logic, but they share the same curve as a starting point. One pricing engine, five ways to earn from it.

Where it stalls without Proxilink

The pricing formula is the easy part of this story. Anyone setting up dynamic rates on their own chargers gets stuck on everything around it. These are the obstacles you run into along the way.

To begin with, the CPO platform allows only one model. The dynamic pricing modules of the common platforms compute the spot price from a chosen source plus one fixed margin, clamped between a minimum and a maximum. That is model 1 from this article, the weakest of the five. An optimum that differs by the hour does not fit in a field labelled "fixed margin".

Nor can you get your own curve in. The price sources are read-only: you can select spot feeds but not inject prices you calculated yourself, and there is no endpoint for feeding a source of your own. What remains is translating your curve into OCPI tariff elements with time restrictions, maintaining a separate tariff per charger, and pushing all of it again every day as soon as the day-ahead lands. Daily machinery, in other words, that also has to keep running on the day you are busy with something else.

On top of that sits a trap that fails silently. Pricing happens per connector, and a tariff at connector level overrides the one at charge point level. Attach your dynamic tariff to the wrong layer and the charger keeps selling every session at the old flat rate, with no error and nothing amiss in your dashboard. You only notice in your CDRs, when the revenue does not match the prices you thought you were charging.

Time zones are a second quiet source of errors. Day-ahead prices arrive in UTC while your customer thinks in Brussels wall clock time, with a 23 or 25 hour day twice a year. CDRs carry several timestamps of which only one is the local start time. Grab the wrong field and your whole hourly profile shifts, rendering your elasticity estimate useless without anything raising an error.

Then there is the infrastructure underneath that nobody sees. Storing quarter-hourly schedules without blowing up your tariff history. Freezing the price at the moment the session starts, or you invoice something other than what the customer saw when scanning. Pulling CDRs and distilling usable sessions from them to train your elasticity on. A fallback for the days the day-ahead does not arrive, because a price still has to be there.

None of those steps is impossible on its own. Together they add up to a software project with little to do with charging, and the mistakes in it are exactly the kind you only see after the revenue is already in.

In Proxilink it is plug and play

In the dashboard this is one screen. You pick a strategy, set your base price, your minimum and your maximum, move the aggressiveness slider, and tomorrow's curve is drawn immediately with your own occupancy as the backdrop and a profit estimate underneath. Every change redraws the chart as you work, before you save.

Tick the box for CPO synchronisation and that curve goes to your charge point platform automatically every day, as a full tariff with hourly blocks, including your parking and time tariffs, so roaming sessions settle at the right price too. The elasticity retrains itself weekly on your own sessions.

If after a few weeks it turns out your charger is better off with forward locked than with the AI model, you switch it in the same dropdown. That is what three years of calculating comes down to: the right pricing model does not exist in general, only for a particular charger with a particular demand profile, and you need the data to see which of the five that is for you.

What the five models would do on your charger depends entirely on your own demand profile, your volume and the rate you work with today. You can get a quantified answer to that without installing or switching anything. Or first see how the platform works.

Frequently asked questions

What is dynamic pricing for an EV charger?

Dynamic pricing means the price per kWh varies through the day instead of being fixed. In Proxilink a price is computed for every quarter-hour and fixed in advance in a daily schedule; the price a customer pays is locked at the moment their session starts. Depending on the chosen strategy, that price follows the energy exchange, the occupancy of your charger, or the computed profit optimum.

Isn’t a price that follows the energy exchange always the fairest model?

It is the most explainable model, but not the most profitable, and it is not always the better deal for the customer either. On a charger whose occupancy peaks during the solar trough, an energy-led model discounts the busiest hours and adds a surcharge to hours when nobody charges. In our calculations that comes out around 3 to 4% below a flat rate.

What is price elasticity in EV charging?

Price elasticity measures how much volume you lose when your price rises. Below 1, people charge despite a higher price (typically during peak hours, when charging is a necessity). Above 1, drivers switch to an alternative (typically at night, when routing apps show several options). A charger’s profit optimum depends entirely on that value, and it differs per charger and per hour.

How much extra return does dynamic pricing deliver?

That depends entirely on your demand profile and which model you choose. On a destination charger with an afternoon peak we estimate the spot-driven models at −3 to −4% against a flat rate, the demand-led model at around +3%, and the AI profit optimum at +10 to +21%. On chargers running in production the model estimates its own effect at +5 to +17%. These remain estimates based on your own occupancy and session data.

Doesn’t a dynamic rate simply mean the customer pays more?

Under the AI model they pay less than a flat rate for 15 of the 24 hours. The model drops below the flat rate in the hours when customers are price-sensitive, because that discount pays for itself through extra volume. A hard minimum and maximum price, a fixed daily curve known in advance, and price locking at session start ensure nobody is caught out.

Can I set this up without Proxilink?

The dynamic pricing modules of CPO platforms generally support one model: spot price plus a fixed margin. You cannot inject your own computed curve, because the price sources are read-only. The workaround is to translate your curve into OCPI tariff elements with time restrictions and push those daily — technically possible, but it requires day-ahead integration, quarter-hourly schedules, price locking at invoicing and CDR processing. In Proxilink that is one screen with a synchronisation checkbox.

Back to blog Book a demo