statistics

The Gini Index: How to Measure SEO Traffic Concentration (with R code)

Ever noticed how just a handful of pages on your site get the lion’s share of traffic?
The homepage, the blog, the product page — and then a long tail of pages that together weigh less than those few.

It’s the Pareto principle, we know it well. But “80% of traffic comes from 20% of pages” is a heuristic, not a measurement.
How do we know if our site is more or less concentrated than average? And what if we want to compare two sites — or the same site at two different points in time?

We need an index that quantifies concentration in a single number.
A number that equals 0 when everything is evenly distributed, and 1 when a single page takes it all. In between, the space of all real distributions.

That number exists. It’s called the Gini index, and it measures the concentration of a transferable quantitative variable (a quantity that can be redistributed without changing its total: income, traffic, market share). It was introduced in 1912 by the Italian statistician Corrado Gini specifically to study inequality in income distribution.
Since then, it has become one of the most widely used indicators in economics, sociology — and yes, in SEO analysis too.

Let’s see how it works.

Before we get to the index itself, let’s start with a graphical representation that Gini borrowed from the work of Max Otto Lorenz (1905): the Lorenz curve.

The Lorenz curve

The idea is simple. We sort pages from least to most traffic. On the x-axis we place the cumulative fraction of pages (from 0 to 100%). On the y-axis we place the cumulative fraction of traffic (also from 0 to 100%). Then we connect the dots.

The dashed 45° line is the equality line: if every page received exactly the same amount of traffic, the Lorenz curve would coincide with this line.
The blue curve is the Lorenz curve for real data: it deviates from the diagonal the more traffic is concentrated in few pages.
The blue-shaded area between the line and the curve is the concentration area.

The key point: the Lorenz curve makes visible what a single number cannot tell — the shape of inequality.
Two sites with the same Gini index can have very different curves, as we’ll see shortly.

Corrado Gini (1884–1965)

Gini published his work “Variabilità e mutabilità” (Variability and Mutability) in 1912, building on Lorenz’s ideas. The index that bears his name comes from there: it measures the area between the Lorenz curve and the 45° line, relative to the total area of the triangle underneath.

From curve to index

The Gini index (often denoted by R, from “concentration ratio”) can be defined independently of the curve.

The mean absolute difference is the average of the absolute differences between all possible pairs of values in the distribution: it measures how far apart the values are from each other on average.

R = mean absolute difference / (2 × mean of values)

A value of R = 0 means perfect equality (all pages have the same traffic).
R = 1 means maximum concentration (a single page holds all traffic).
In reality, we move between these extremes: the graph above shows R ≈ 0.61, a medium-high concentration value typical of many real websites.

For context: the Gini index for income distribution in Italy is around 0.33 (ISTAT 2023 data).
A website typically has much higher values, because traffic tends to concentrate more extremely than income.

An important limitation. The Gini index is a synthetic indicator: it summarises concentration in a single number, but two very different distributions can produce the same value. A site with a few extremely strong pages and many near-zero ones can have Gini = 0.6, exactly like a site with a more gradual distribution. The Lorenz curve helps see the difference — but the number alone is not enough.

In the digital world, traffic often follows a power law (sometimes called Zipf’s law), with a very long tail of pages receiving very few visits. Gini does not distinguish this type of distribution from one with a shorter tail: the same value can hide very different tails, which is why it should always be accompanied by the Lorenz curve.

Beware when comparing sites of different sizes. The Gini estimator computed on few pages (say n < 50) tends to overestimate true concentration: this is a known bias, which is why a corrected version multiplies by n/(n−1). A small site will appear structurally more concentrated than a large one, even with the same underlying distribution. Comparing Gini values computed on very different numbers of pages is misleading.

Three common mistakes with the Gini index

1. “Gini tells us how many pages concentrate traffic” — No. Gini tells us how unequal the distribution is, not how many pages are above a certain threshold. Two sites with Gini = 0.6 can have very different patterns: one with a few very strong pages and many near-zero, another with a more gradual distribution. The Lorenz curve helps distinguish the cases.

2. “Gini can be used on any variable” — Careful. Gini only makes sense for transferable variables, that is, variables where summing values and redistributing them is meaningful. Income qualifies (the sum of incomes is total income). Traffic sessions qualify (the sum of sessions is total traffic). Conversion rate does not: “redistributing” conversion rates makes no sense.

3. “Gini is the same as standard deviation” — No. Standard deviation measures absolute dispersion, Gini measures relative concentration. Two distributions with the same standard deviation can have very different Gini indices, and vice versa.

Try it yourself

Here are the session counts (last 30 days) for 8 pages on an imaginary site:

PageSessions
Homepage8,200
Blog5,100
Products2,800
About us950
Contact720
Services450
Client area310
Work with us180

Try to answer:

  1. At a glance: do you think the Gini index will be closer to 0.3, 0.5, or 0.7?
  2. Which are the top two pages by traffic? What fraction of total traffic do they account for?
  3. If we added a ninth page with 50 sessions, would the Gini index increase or decrease?

Take a moment to think — then let’s work through the solution in R.

Computing the Gini index in R

Let’s calculate the Gini index on the exercise data. In R we can implement the definition directly:

Delta <- function(variable) {
  n <- length(variable)
  avg <- mean(variable)
  sorted_var <- sort(variable)
  (4 * sum((1:n) * sorted_var) / n - 2 * avg * (n + 1)) / (n - 1)
}

sessions <- c(8200, 5100, 2800, 950, 720, 450, 310, 180)

# Note: this formula avoids computing all
# n(n-1)/2 pairs explicitly (efficient rewrite)
gini <- Delta(sessions) / (2 * mean(sessions))
gini

# Lorenz curve in one go with the ineq package
library(ineq)
gini_ineq <- Gini(sessions)
lc <- Lc(sessions)
plot(lc)

The result? R ≈ 0.58. A high concentration value, as expected for a site with a dominant homepage.

Answers:

  1. Was it closer to 0.7? Actually 0.58, but if you thought “between 0.5 and 0.7” you were on the right track.
  2. Homepage and Blog together make 13,300 out of 18,710 total sessions — about 71%. Just over 70% of traffic concentrated in 25% of the pages.
  3. A ninth page with 50 sessions would increase the Gini index, because we’re adding a tail page with very little traffic (50 becomes the new minimum). In general, though, the effect depends on where the new value falls: if it were close to the mean, the outcome would be ambiguous.

The Gini index tells us how much traffic is concentrated, but not why.
Two sites with the same Gini can have completely different dynamics: one because very few pages perform extremely well, another because a great many pages perform very poorly. The diagnosis is the same (high concentration), but the cure differs.

In the next article, we’ll look at breaking down concentration by traffic source (organic, direct, social, referral) — and figure out where to act first.


Further reading

For a brilliant exploration of statistical thinking, inequality measures, and how to read numbers without being fooled: The Art of Statistics by David Spiegelhalter offers a masterful blend of rigour and clarity, with illuminating pages on the Gini index and the Lorenz curve.

Paolo Gironi

Recent Posts

Keyword Clustering: grouping thousands of queries with K-means and hierarchical clustering

It happens with every reasonably serious project: you export the keyword list from Search Console…

3 weeks ago

Expected vs Actual CTR: finding the pages that earn fewer clicks than their position deserves

Anyone who spends their days inside Search Console knows that little nagging feeling: a page…

4 weeks ago

Naive Bayes: classifying search intent with Bayes’ theorem

In the article on the multi-armed bandit we used Bayes to decide between variants: shifting…

4 weeks ago

Multi-armed bandit: optimising the variants while the test is still running

In the article on Bayesian A/B testing we compared two variants at a fixed sample…

4 weeks ago

Bayesian A/B Testing: not just “whether” B beats A, but “by how much”

In the article on classic A/B testing we saw how to compare two variants with…

4 weeks ago

Bayesian Conversion Rate Estimation: how much can we trust limited data

In the article on the foundations of Bayesian statistics, we saw how Bayesian updating works…

4 weeks ago