Salta al contenuto
NetCov

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.

html
<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".

python
# 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_code

Anteprima 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 /coverage con /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:

html
<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:

javascript
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);
  });
}