Breaking
26 Sep 2026, Sat

EDITORIA. I dati ADS aggiornati confermano il crollo della carta: Corriere della Sera -29%, Repubblica -39% in quattro anni. Il digitale rallenta la caduta ma non la ferma

generic-feature-photo

Sono passati ben quattro anni dal nostro ultimo articolo dedicato all’analisi della diffusione dei quotidiani in Italia. La recente decisione del principale tra essi, il Corriere della Sera, di ridurre la foliazione ci ha convinto che fosse il momento di tornare a guardare i numeri e magari fare qualche considerazione: anche perché, come sostenevamo allora, la correlazione tra vera libertà di stampa e voglia dei lettori di acquistare un quotidiano o abbonarsi ad una edizione digitale non è mai stata smentita.

Sintesi

La tiratura di settembre crolla ancora su tutte le testate monitorate: Corriere della Sera -29% in quattro anni (da 242.534 a 171.068 copie), La Repubblica -39% (da 183.267 a 112.434), Il Sole 24 Ore -30% (da 77.831 a 54.208).
La proiezione lineare del 2021 dava Repubblica a zero copie nel 2028: rifatta oggi sui dati 2015-2025, la stessa proiezione dà ancora il 2028.
Per la prima volta distinguiamo cartacea pagata e digitale venduto: al Sole 24 Ore il digitale (65.624 copie) supera già il cartaceo (29.478).
Sommando cartacea e digitale, il crollo rallenta ma non si ferma: il totale complessivo del Corriere passa da 255.119 (2021) a 210.471 (2025), -17% anziché -29%.
MF Milano Finanza, classificata da ADS come settimanale e non come quotidiano, è la testata più stabile: -11% in due anni.
ADS non certifica dati di ascolto/abbonamento podcast: quel pezzo di “contenuto fruito” resta fuori da ogni conteggio ufficiale.

La carta si accorcia

Da ottobre 2026 il Corriere della Sera taglia le pagine: l’edizione nazionale passa da 21-22 a 18-19 pagine, alcune edizioni locali (Bergamo, Brescia, Bologna, Firenze, Napoli, Bari, Trento) scendono a 8 pagine. È la parte più visibile di un piano di riorganizzazione digital first annunciato dalla direzione, che sposta redattori dalla carta al digitale.

ADS, quattro anni dopo

ADS (Accertamenti Diffusione Stampa) ha cambiato pelle: il vecchio motore di ricerca CSV del sito adsnotizie.it usato nel 2021 non esiste più, sostituito da file Excel mensili e annuali scaricabili testata per testata. Il che, detto per inciso, è anche un piccolo miglioramento di trasparenza.

Novità più sostanziale: da qualche anno ADS pubblica anche un totale ufficiale cartacea + digitale per ogni testata — la somma che nel 2021 dicemmo di non riuscire a costruire in modo convincente. Oggi esiste, ed è la base del secondo grafico di questo articolo.

Niente più R

Nel 2021 usavamo il linguaggio R, codice incluso in fondo all’articolo perché chiunque potesse riverificare i conti. Questa volta l’estrazione dai file ADS e le regressioni sono state fatte in Python: stesso principio di allora, stessa scelta di pubblicare tutto — dati, codice e link alle fonti sono in appendice, in fondo a questo articolo.

Il metodo aggiornato

Restiamo su Corriere della Sera, La Repubblica, MF Milano Finanza e aggiungiamo Il Sole 24 Ore, escluso nel 2021 per la vicenda della diffusione gonfiata dell’era Napoletano ma oggi pienamente confrontabile. Il dato scelto resta lo stesso: settembre di ogni anno, dal 2015 (primo anno con dettaglio digitale nel nuovo formato ADS) al 2025.

Ma per la prima volta separiamo tre livelli: tiratura (copie stampate, il vecchio indicatore), diffusione pagata distinta in cartacea e digitale (vendite e abbonamenti effettivamente venduti), e totale cartacea + digitale certificato da ADS, che include anche copie digitali abbinate all’abbonamento cartaceo, promozionali ed estero.

Tiratura media ADS 2015-2025: Corriere della Sera, La Repubblica, Il Sole 24 Ore

Corriere della Sera

La tiratura di settembre passa da 242.534 copie (2021) a 171.068 (2025): -29% in quattro anni, dopo il -74% già maturato tra il 1998 (918.000 copie) e il 2021. Il crollo non rallenta.

La Repubblica

Da 183.267 a 112.434 copie: -39% in quattro anni, il calo percentuale più marcato tra i quotidiani generalisti. La regressione lineare 2015-2025 proietta lo zero copie nel 2028 — esattamente l’anno che la regressione del 2021 (costruita su dati 1998-2021) già indicava. A quattro anni di distanza, Repubblica è rimasta sulla traiettoria prevista, copia per copia.

Il Sole 24 Ore

Da 77.831 a 54.208 copie di tiratura: -30%. Ma è la testata dove la distinzione cartacea/digitale conta di più: nel 2025 la diffusione digitale venduta (65.624 copie) è più del doppio di quella cartacea pagata (29.478). Un quotidiano economico-finanziario, letto da un pubblico abituato a pagare per l’informazione online, è oggi più digitale che di carta.

MF Milano Finanza

ADS la classifica come settimanale e non come quotidiano. I dati disponibili in questo formato coprono solo il 2023-2025, ma mostrano la testata più stabile del lotto: tiratura da 46.241 a 41.230 copie, -11% in due anni, contro il -20/-25% delle altre nello stesso periodo. Conferma quanto scrivevamo nel 2021: un segmento verticale ben definito protegge meglio della generalista.

Composizione cartacea pagata vs digitale venduta vs totale, settembre 2025

Il digitale rallenta, non ferma

Sommando cartacea e digitale (il totale ufficiale ADS), il quadro migliora ma non si ribalta. Il Corriere passa da 255.119 (2021) a 210.471 (2025): -17% invece di -29%. Repubblica da 157.228 a 131.673: -16% invece di -39%. Il Sole 24 Ore da 134.533 a 113.068: -16% invece di -30%.

Rifacendo la regressione sul totale anziché sulla sola tiratura, lo zero copie del Corriere si sposta dal 2033 al 2043: un decennio di ossigeno in più, comprato dal digitale. Per Repubblica e Sole 24 Ore il guadagno è più modesto, due-tre anni.

Quello che ADS non misura

Ci era stato chiesto di includere, se possibile, gli abbonati podcast delle testate. Non lo abbiamo fatto: ADS certifica diffusione cartacea e copie digitali (app, e-edition, abbonamenti web), non ascolti audio. I podcast editoriali di Corriere, Repubblica e Sole 24 Ore vivono su piattaforme come Spotify e Apple Podcasts, fuori da qualunque accertamento indipendente pubblico: un buco di trasparenza che, a differenza della carta e del digitale testuale, nessuno certifica.

Quattro anni dopo, la fotografia è più sfumata ma non più confortante. La carta continua a perdere terreno alla stessa velocità di prima; il digitale non compensa, ma allunga la vita del prodotto giornale di qualche anno prezioso. Resta il punto che facevamo nel 2021: dove i lettori continuano a pagare — in edicola o online — c’è ancora un’informazione che si regge sulle proprie gambe. Dove smettono di pagare, prima o poi, smette anche il giornale. (M.H.B. per NL)


Appendice: dati, codice e fonti

Come nel 2021, pubblichiamo dati grezzi e codice per chi vuole rifare i conti da sé.

Tabella dati (settembre 2015-2025)

Testata Anno Tiratura Cartacea pagata Digitale venduto Totale cart.+dig.
Corriere della Sera 2015 394.784 229.042 57.719 369.391
Corriere della Sera 2016 333.841 216.578 48.040 310.437
Corriere della Sera 2017 315.053 200.909 49.099 284.801
Corriere della Sera 2018 303.517 197.522 49.817 278.334
Corriere della Sera 2019 293.393 187.668 50.695 268.950
Corriere della Sera 2020 256.727 166.571 69.849 256.831
Corriere della Sera 2021 242.534 156.680 80.159 255.119
Corriere della Sera 2022 231.603 152.296 93.642 262.915
Corriere della Sera 2023 203.310 132.837 100.041 247.236
Corriere della Sera 2024 190.145 120.561 97.676 231.661
Corriere della Sera 2025 171.068 105.655 92.225 210.471
La Repubblica 2015 391.682 231.656 57.122 327.329
La Repubblica 2016 340.745 222.816 29.870 269.474
La Repubblica 2017 288.998 174.217 28.977 221.531
La Repubblica 2018 254.156 153.284 45.019 215.029
La Repubblica 2019 254.970 147.411 46.569 203.515
La Repubblica 2020 217.203 132.430 51.437 187.327
La Repubblica 2021 183.267 104.677 51.193 157.228
La Repubblica 2022 163.251 89.456 46.298 137.130
La Repubblica 2023 136.337 76.322 41.269 150.701
La Repubblica 2024 120.616 67.058 40.515 145.082
La Repubblica 2025 112.434 58.993 38.033 131.673
Il Sole 24 Ore 2015 199.945 125.303 180.109 368.754
Il Sole 24 Ore 2016 162.563 97.791 56.784 193.611
Il Sole 24 Ore 2017 120.132 75.909 59.561 168.007
Il Sole 24 Ore 2018 113.522 66.450 62.803 159.495
Il Sole 24 Ore 2019 91.938 57.989 55.452 141.478
Il Sole 24 Ore 2020 89.471 53.168 63.922 143.540
Il Sole 24 Ore 2021 77.831 45.002 68.736 134.533
Il Sole 24 Ore 2022 68.643 40.605 71.097 129.979
Il Sole 24 Ore 2023 63.731 36.705 69.146 123.573
Il Sole 24 Ore 2024 61.297 33.336 67.287 117.886
Il Sole 24 Ore 2025 54.208 29.478 65.624 113.068
MF Milano Finanza 2023 46.241 29.672 6.220 36.878
MF Milano Finanza 2024 41.870 24.819 6.463 32.498
MF Milano Finanza 2025 41.230 24.043 7.638 32.718

Dato di settembre di ogni anno. “Cartacea pagata” = vendite individuali + abbonamenti individuali + vendite multiple + abbonamenti multipli, tutti cartacei. “Digitale venduto” = vendite + abbonamenti digitali (individuali e multipli), esclude copie digitali abbinate a un abbonamento cartaceo e copie omaggio. “Totale cartacea + digitale” = colonna ufficiale ADS (include anche copie abbinate, promozionali ed estero). Somma “Cartacea pagata” + “Digitale venduto” = colonna ufficiale ADS “Totale diffusione pagata Italia” — verificato riga per riga, scarto zero salvo arrotondamenti di 1 copia.

Fonti dirette (file ADS scaricabili)

  • Dati mensili (settembre 2015-2025): https://www.adsnotizie.it/Dati/downloadDMS?mese=9&anno={2015..2025}&periodicita={1|6}&nomeReport=DMSFilePubblicato_3 (periodicità 1 = quotidiani, per Corriere della Sera / La Repubblica / Il Sole 24 Ore; periodicità 6 = settimanali, per MF Milano Finanza dal 2023)
  • Dati annuali certificati: 2021, 2022, 2023, 2024
  • Pagina di consultazione: adsnotizie.it/Dati/DMS_Page e adsnotizie.it/Dati/DatiMedi_Page

Codice: estrazione colonne dai file ADS

Individua le colonne per testo dell’intestazione (ADS cambia leggermente la struttura tra un anno e l’altro) invece che per indice fisso.

#!/usr/bin/env python3
"""Header-text-driven parser: locates columns by matching header text across the
first 4 rows of each ADS sheet, rather than trusting fixed indices (which shift
across years / report versions). Applies uniformly to monthly DMS files and
annual Certificati/Dichiarati files."""
import openpyxl
import csv
import re
import warnings
warnings.filterwarnings("ignore")

TARGETS = {
    "CORRIERE DELLA SERA": "Corriere della Sera",
    "REPUBBLICA (LA)": "La Repubblica",
    "SOLE 24 ORE (IL)": "Il Sole 24 Ore",
    "MILANO FINANZA": "MF Milano Finanza",
}


def norm(s):
    if s is None:
        return ""
    return re.sub(r"\s+", " ", str(s).replace("\xa0", " ")).strip().upper()


def header_rows(ws, max_rows=5):
    rows = []
    for i, row in enumerate(ws.iter_rows(values_only=True)):
        rows.append(row)
        if i >= max_rows - 1:
            break
    return rows


def find_col(headers, ncols, *needles, exclude=()):
    """Match needles against each column's OWN header text only (no forward-
    fill across merged cells) - every anchor label we rely on is written once,
    directly in its own column, in every ADS report variant seen. Forward-
    filling group labels caused false matches on sibling leaf columns."""
    matches = []
    for c in range(ncols):
        combined = " ".join(norm(hr[c]) for hr in headers if c < len(hr))
        if all(n in combined for n in needles) and not any(e in combined for e in exclude):
            matches.append(c)
    return matches


def with_tier_pair(cols, ncols):
    """The %>=30 / %10-30 (and similar) tiers share one label written only on
    the first column; the second (anchor+1) carries just the tier percentage.
    Expand each anchor match to include its adjacent tier column."""
    out = set()
    for c in cols:
        out.add(c)
        if c + 1 < ncols:
            out.add(c + 1)
    return sorted(out)


def parse_sheet(ws, anno_label, tipo, source):
    rows = list(ws.iter_rows(values_only=True))
    if not rows:
        return []
    ncols = max(len(r) for r in rows[:6])
    headers = rows[:4]

    name_col = 0  # Testata is always first column in every variant seen
    tiratura_cols = find_col(headers, ncols, "TIRATURA")
    dig_ind_cols = with_tier_pair(find_col(headers, ncols, "VENDITE COPIE DIGITALI INDIVIDUAL"), ncols)
    dig_mult_cols = with_tier_pair(find_col(headers, ncols, "VENDITE MULTIPLE DIGITALI"), ncols)
    dig_abbinate_cols = with_tier_pair(find_col(headers, ncols, "COPIE DIGITALI ABBINATE"), ncols)
    dig_promo_cols = find_col(headers, ncols, "COPIE DIGITALI PROMOZIONALI")
    pagata_italia_cols = find_col(headers, ncols, "DIFFUSIONE PAGATA", "ITALIA")
    totale_cart_dig_cols = find_col(headers, ncols, "CARTACEA", "DIGITALE", exclude=("TIRATURA",))
    # single-column leaf labels: raw (unfilled) match is unambiguous
    vendite_ind_cart_cols = find_col(headers, ncols, "VENDITE INDIVIDUALI CARTACEE")
    abb_ind_cart_cols = find_col(headers, ncols, "ABBONAMENTI INDIVIDUALI CARTACEI")
    vendite_mult_cart_cols = find_col(headers, ncols, "VENDITE MULTIPLE", "CARTACEE PAGATE")
    abb_mult_cart_cols = find_col(headers, ncols, "ABBONAMENTI MULTIPLI CARTACEI")

    tiratura_col = tiratura_cols[0] if tiratura_cols else None
    pagata_col = pagata_italia_cols[0] if pagata_italia_cols else None
    grand_total_col = totale_cart_dig_cols[0] if totale_cart_dig_cols else None
    # digital SOLD (subscriptions/purchases) only - excludes bundled copies
    # given free with a print sub and promotional/omaggio copies, so that
    # print_paid + digital_sold reconciles exactly to the official
    # "Totale diffusione pagata Italia" column (verified below).
    digital_cols = dig_ind_cols + dig_mult_cols
    print_paid_cols = vendite_ind_cart_cols + abb_ind_cart_cols + vendite_mult_cart_cols + abb_mult_cart_cols

    out = []
    for row in rows:
        name = row[name_col] if name_col < len(row) else None
        if not name:
            continue
        name_up = norm(name)
        if name_up not in TARGETS:
            continue
        # sanity check this is a data row: anno-ish numeric should appear somewhere in cols 4-7
        def g(col):
            if col is None or col >= len(row):
                return None
            v = row[col]
            return v if isinstance(v, (int, float)) else None

        tiratura = g(tiratura_col)
        pagata = g(pagata_col)
        grand_total = g(grand_total_col)
        digital_total = sum(g(c) or 0 for c in digital_cols) if digital_cols else None
        print_paid_total = sum(g(c) or 0 for c in print_paid_cols) if print_paid_cols else None
        if tiratura is None:
            continue  # header/blank row picked up by mistake
        check = None
        if print_paid_total is not None and digital_total is not None and pagata is not None:
            check = (print_paid_total + digital_total) - pagata
        out.append({
            "testata": TARGETS[name_up],
            "source": source,
            "tipo": tipo,
            "anno": anno_label,
            "tiratura": tiratura,
            "print_pagato": print_paid_total,
            "digitale_venduto": digital_total,
            "diffusione_pagata_italia": pagata,
            "totale_cartacea_digitale": grand_total,
            "_check_print_plus_digital_minus_pagata": check,
        })
    return out


ALL_ROWS = []

# Monthly September snapshots 2015-2025 (periodicita 1 = quotidiani, 6 = settimanali)
for anno in range(2015, 2026):
    for per in (1, 6):
        fname = f"dms_{anno}_09_per{per}.xlsx"
        try:
            wb = openpyxl.load_workbook(fname, data_only=True)
        except FileNotFoundError:
            continue
        ws = wb.active
        ALL_ROWS.extend(parse_sheet(ws, anno, "DMS-settembre", fname))

# Annual certified/declared files
ANNUAL_FILES = [
    ("ReportMediaPeriodo_2021.xlsx", 2021, "CERT-annuale"),
    ("DatiCertificati2022.xlsx", 2022, "CERT-annuale"),
    ("DatiCertificati2023.xlsx", 2023, "CERT-annuale"),
    ("Certificati_2024.xlsx", 2024, "CERT-annuale"),
]
for fname, anno, tipo in ANNUAL_FILES:
    wb = openpyxl.load_workbook(fname, data_only=True)
    for sheet in wb.sheetnames:
        ALL_ROWS.extend(parse_sheet(wb[sheet], anno, tipo, fname))

FIELDS = ["testata", "source", "tipo", "anno", "tiratura", "print_pagato", "digitale_venduto", "diffusione_pagata_italia", "totale_cartacea_digitale"]
with open("ads_clean.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=FIELDS)
    writer.writeheader()
    for r in ALL_ROWS:
        writer.writerow({k: r[k] for k in FIELDS})

print(f"Wrote {len(ALL_ROWS)} rows to ads_clean.csv\n")
bad = [r for r in ALL_ROWS if r["_check_print_plus_digital_minus_pagata"] not in (0, None)]
print(f"Reconciliation mismatches (print_pagato+digitale_venduto != diffusione_pagata_italia): {len(bad)}")
for r in bad:
    print(" MISMATCH", r["testata"], r["anno"], r["source"], "delta=", r["_check_print_plus_digital_minus_pagata"])
for r in ALL_ROWS:
    print(r)

Codice: regressione lineare (equivalente Python di lm() in R)

import numpy as np
# x = anni (2015..2025), y = tiratura (o totale cartacea+digitale) di ogni anno
slope, intercept = np.polyfit(x, y, 1)
anno_zero_copie = -intercept / slope