Widget
Il widget copertura in 3 righe
Incolla il contenitore dove vuoi il form, carichi uno script e hai il widget di verifica: comune, indirizzo e le reti disponibili con gli operatori. Funziona subito in modalità demo (senza chiave); per la produzione basta un proxy lato server con la tua chiave.
Passo 1 · HTML
Attributi opzionali: data-city, data-address, data-endpoint (proxy personale, default: demo). Comune e indirizzo sono campi di ricerca con suggerimenti: si seleziona da tastiera (frecce/Invio/Esc) o col mouse.
<div data-netcov-widget
data-city="Napoli"
data-address="via Toledo 21">
</div>
<script src="https://netcov.io/netcov-widget.js" async defer></script>Passo 2 · Produzione: il proxy
La chiave vive solo sul server. Il widget chiama il tuo backend, che inoltra con l’header Authorization. Poi imposta data-endpoint="https://tuosito.it/coverage".
# Flask: proxy server-side (la chiave NON va nel browser)
@app.post("/coverage")
def coverage():
r = requests.get("https://api.netcov.io/coverage/italy",
params={"address": f'{request.form["address"]}, {request.form["city"]}'},
headers={"Authorization": "Bearer LA_TUA_CHIAVE"})
return r.json(), r.status_codeAnteprima live
L’anteprima usa la modalità demo (chiave lato server, quota dedicata). Il widget mostra sempre l’attribuzione CC BY 4.0 obbligatoria (BroadbandMap di Agcom + ANNCSU).
Alternativa WordPress
Il plugin netcov-coverage ↗ include blocco Gutenberg, shortcode e proxy REST integrato (chiave mai esposta al browser).
Ricerca assistita e degradazione graduale
- Il campo comune suggerisce i comuni (minimo 2 caratteri, debounce 250 ms, cache client di 60 secondi per coppia città più testo).
- Il campo indirizzo suggerisce vie e civici: scegliendo un civico il widget invia il suo codice stabile (
?code=…, insieme a città e indirizzo per compatibilità); scegliendo una via o scrivendo testo libero invia città più indirizzo come prima. I codici interni non vengono mai mostrati ai visitatori. - L’URL di autocomplete deriva dal tuo endpoint sostituendo il suffisso
/coveragecon/autocomplete(stesso pattern proxy della copertura). - Degradazione graduale: se il proxy di autocomplete non esiste ancora (404) o non risponde, il widget resta un form con input semplici e verifica funzionante — non si rompe mai.
Sicurezza: non mettere mai una chiave standard in JavaScript pubblico. Per le pagine pubbliche usa una chiave browser con allowlist di origini (piano browser); per le chiavi standard usa il proxy server-side qui sopra.
Integrazione sicura
Le chiavi API devono restare lato server. Chi espone una chiave standard nel browser la regala a chiunque legga il sorgente: può essere riusata da altri siti e consumare la tua quota. Il proxy di produzione qui sopra esiste proprio per questo: il widget chiama il tuo backend e la chiave vive solo lì.
Alternativa senza proxy: chiave browser. Le chiavi con piano browser hanno una allowlist di origini, sono accettate solo in GET e solo quando l’host di Origin (o Referer come ripiego) corrisponde a una voce consentita. Incolla la chiave in data-key del tag del widget e non serve alcun proxy:
<div data-netcov-widget
data-key="LA_CHIAVE_BROWSER"
data-city="Napoli"
data-address="via Toledo 21">
</div>
<script src="https://netcov.io/netcov-widget.js" async defer></script>Form pubblici: debounce e cache. L’autocomplete nei form pubblici va chiamato con debounce di almeno 250 ms e una cache client di 60 secondi per coppia città più testo digitato, per non sprecare quota a ogni tasto:
let timer;
const cache = new Map(); // chiave: city+q, valore: { at, data }
async function suggerisci(city, q) {
const chiave = city + "|" + q;
const adesso = Date.now();
const nota = cache.get(chiave);
if (nota && adesso - nota.at < 60000) return nota.data;
clearTimeout(timer);
return new Promise((resolve) => {
timer = setTimeout(async () => {
const r = await fetch(
"https://api.netcov.io/autocomplete?city="
+ encodeURIComponent(city)
+ "&address=" + encodeURIComponent(q),
{ headers: { Authorization: "Bearer LA_CHIAVE_BROWSER" } }
);
const data = await r.json();
cache.set(chiave, { at: Date.now(), data });
resolve(data);
}, 250);
});
}