HairAlert

Kennis en kansen voor Kappers.

Jij richt je op je klanten, wij op je concurrenten. Wees als eerste op de hoogte met je eigen lokale concurrentierapport.

Nu voor slechts €39 per maand!


Google Maps

Maps monitoren op zijn best. Nieuwe rivalen, lokale updates, en elke sappige review. Weet altijd wat er speelt in jouw omgeving.


Social Media

We volgen je concurrenten op Facebook en Instagram. We scannen hun berichten en filteren de ruis. We melden wat er toe doet.


Website Activiteit

Een stille prijswijziging of een nieuwe behandeling. We scannen de websites van je concurrenten en niets glipt ongemerkt voorbij.


Social Media

We volgen je concurrenten op Facebook en Instagram. We scannen hun berichten en filteren de ruis. We melden wat er toe doet.


Website Activiteit

Een stille prijswijziging of een nieuwe behandeling. We scannen de websites van je concurrenten en niets glipt ongemerkt voorbij.


Altijd Op Hoogte

Elk signaal uit elke bron, samengebracht in één compact rapport. Makkelijk te lezen en rechtstreeks in je inbox bezorgd.


Lokaal Inzicht

Lokaal maar volledig. Ons eigen monitoringsysteem volgt elk platform waarop je concurrenten actief zijn. Het volgt elke verandering door de tijd heen, zodat jij altijd het volledige beeld ziet.

Prijswijzigingen, nieuwe behandelingen of diensten, vacatures en openingstijden.

Gun jezelf onze geavanceerde marktinformatie voor slechts €39 per maand!

Geen verplichtingen, stop wanneer je wilt.


Altijd Online

We monitoren je concurrenten continu.
We volgen hun profielen en websites en signaleren elke relevante verandering.

.

Rapport Op Maat

Alles wat we vinden wordt gebundeld, gefilterd en gepolijst tot één compact rapport. Afgestemd op jouw regio en rechtstreeks in je inbox bezorgd, klaar om te lezen, elke week.

.

Geen Installatie

Je hoeft niets te installeren om te beginnen. We sturen je een scan van je concurrenten-portfolio en beginnen die direct te monitoren. Veranderingen zie je pas vanaf het tweede rapport. Dit alles valt nog binnen je gratis proefperiode.


Contact Ons

Vragen, of opmerkingen? Laat een bericht achter en we nemen contact met je op.


Start Gratis

HairAlert is de eerste maand gratis. Jij richt je op je klanten, wij op je concurrenten. Blijf voorop met HairAlert.

(function waitForStripe() { if (!window.Stripe) return setTimeout(waitForStripe, 50); initStripe(); })(); async function initStripe() { const msg = document.getElementById("pay-msg"); const stripe = Stripe("pk_live_51Sjl10JU2qjtla5tRzk7kDisUSJuFkxeEnzm61Nm62OliMY7KMnTvzzPDYcXBa5ohwRVbAJg03qmK40bXGRjiFij00E2u7k1IR"); let place_id = ""; try { place_id = sessionStorage.getItem("ma_place_id") || ""; if (!place_id) { const hash = window.location.hash || ""; const qi = hash.indexOf("?"); if (qi !== -1) { const params = new URLSearchParams(hash.slice(qi + 1)); place_id = params.get("place_id") || ""; } } if (!place_id) { const params = new URLSearchParams(window.location.search); place_id = params.get("place_id") || ""; } } catch(e) {} let plan = "insights"; try { const hash = window.location.hash || ""; const qi = hash.indexOf("?"); let found = null; if (qi !== -1) { const hashParams = new URLSearchParams(hash.slice(qi + 1)); found = hashParams.get("plan"); } if (!found) { const queryParams = new URLSearchParams(window.location.search); found = queryParams.get("plan"); } if (found) plan = found; } catch(e) {} const elements = stripe.elements({ locale: "nl" }); const card = elements.create("card", { style: { base: { fontFamily: "Inter, system-ui, sans-serif", fontSize: "16px", color: "#585D6B" } } }); card.mount("#pay-card-element"); const intentRes = await fetch("https://mapalert-places-api.vercel.app/api/x_create-setup-intent", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ place_id: place_id }) }); const intentData = await intentRes.json(); if (!intentData.client_secret) { msg.textContent = "Betaling kon niet worden geladen. Vernieuw de pagina."; return; } const email = intentData.email || ""; document.getElementById("pay-submit-btn").addEventListener("click", async () => { msg.textContent = "We zetten je gratis maand klaar..."; const name = document.getElementById("pay-name").value.trim(); if (!name) { msg.textContent = "Vul de naam van de kaarthouder in."; return; } const setupResult = await stripe.confirmCardSetup( intentData.client_secret, { payment_method: { card, billing_details: { name: name, email: email } } } ); if (setupResult.error) { msg.textContent = setupResult.error.message; return; } const paymentMethodId = setupResult.setupIntent.payment_method; const subRes = await fetch("https://mapalert-places-api.vercel.app/api/x_create-subscription", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ place_id: place_id, email: email, payment_method: paymentMethodId, cardholder_name: name, plan: plan, product: "hairalert", currency: "EUR" }) }); const subData = await subRes.json(); if (!subRes.ok || !subData.ok) { msg.textContent = subData.error || "Het aanmaken van het abonnement is mislukt."; return; } sessionStorage.removeItem("ma_place_id"); window.location.href = "/#verified"; }); }

✓ Automatische monitoring
✓ Wekelijkse updates
✓ Altijd opzegbaar
€39 p/m


Bedankt!

Nogmaals bedankt voor je bericht. We reageren zo snel mogelijk. Je kunt altijd een persoonlijk antwoord van ons verwachten.


Probeer Nu!

Vind je salon door simpelweg de postcode
en naam in te voeren. We verifiëren je bedrijfsprofiel binnen enkele seconden.

(() => { function ready(fn) { if (document.readyState !== "loading") { fn(); } else { document.addEventListener("DOMContentLoaded", fn); } } ready(() => { const root = document.getElementById("xwf-app"); if (!root) return; const API_BASE = "https://mapalert-places-api.vercel.app"; const NEXT = root.getAttribute("data-next") || "/#select"; const byId = (id) => document.getElementById(id); const setMsg = (t, isErr) => { const m = byId("xwf-msg"); m.textContent = t || ""; m.style.color = isErr ? "#c0392b" : "#8a93a0"; }; let business = null; let busy = false; try { const sp = sessionStorage.getItem("xw_find_postcode"); const sn = sessionStorage.getItem("xw_find_name"); if (sp) byId("xwf-pc").value = sp; if (sn) byId("xwf-bn").value = sn; } catch (e) {} const doFind = async () => { if (busy) return; const pc = byId("xwf-pc").value.trim(); const bn = byId("xwf-bn").value.trim(); if (!pc || !bn) { return setMsg("Vul je postcode en salonnaam in.", true); } busy = true; setMsg("We zoeken je salon..."); try { const r = await fetch(API_BASE + "/api/xw_preview", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ postcode: pc, business_name: bn }) }); const d = await r.json(); busy = false; if (d && d.chain_detected) { return setMsg("Dat lijkt een landelijke keten. HairAlert is gemaakt voor zelfstandige, lokale salons.", true); } if (!r.ok || !d || !d.place_id) { return setMsg((d && d.error) || "We konden je salon niet vinden. Controleer de gegevens en probeer opnieuw.", true); } business = d; byId("xwf-c-name").textContent = d.name || ""; byId("xwf-c-addr").textContent = [d.address_line1, d.address_city].filter(Boolean).join(", ") || d.address || ""; const cat = byId("xwf-c-cat"); if (d.category_display) { cat.textContent = d.category_display; cat.style.display = ""; } else { cat.style.display = "none"; } setMsg(""); byId("xwf-modal").style.display = "flex"; } catch (e) { busy = false; setMsg("Er ging iets mis. Probeer het opnieuw.", true); } }; const confirmYes = () => { if (!business || !business.place_id) return; try { sessionStorage.setItem("xw_business", JSON.stringify(business)); sessionStorage.setItem("xw_own_place_id", business.place_id); sessionStorage.setItem("xw_find_postcode", byId("xwf-pc").value.trim()); sessionStorage.setItem("xw_find_name", byId("xwf-bn").value.trim()); } catch (e) {} window.location.href = NEXT; }; const confirmNo = () => { byId("xwf-modal").style.display = "none"; }; byId("xwf-find").addEventListener("click", doFind); byId("xwf-yes").addEventListener("click", confirmYes); byId("xwf-no").addEventListener("click", confirmNo); }); })();

.


Uw Portfolio

Selecteer tot 12 concurrenten en we beginnen ze te monitoren. We volgen ze op Google Maps, social media en hun websites.

(() => { function ready(fn) { if (document.readyState !== "loading") { fn(); } else { document.addEventListener("DOMContentLoaded", fn); } } ready(() => { const root = document.getElementById("xws-app"); if (!root) return; const API_BASE = "https://mapalert-places-api.vercel.app"; const NEXT = root.getAttribute("data-next") || "/#email"; const PRESELECT = parseInt(root.getAttribute("data-preselect"), 10) || 3; const MAX_PICK = parseInt(root.getAttribute("data-max"), 10) || 12; const byId = (id) => document.getElementById(id); const setMsg = (t, isErr) => { const m = byId("xws-msg"); m.textContent = t || ""; m.style.color = isErr ? "#c0392b" : "#8a93a0"; }; const st = { business: null, competitors: [], nextToken: null, busy: false }; try { st.business = JSON.parse(sessionStorage.getItem("xw_business") || "null"); } catch (e) {} if (!st.business || !st.business.place_id) { setMsg("Je sessie is verlopen. Begin opnieuw.", true); return; } const country = st.business.country_code || st.business.address_country || ""; const fmtDist = (km) => { if (km == null) return ""; const c = (country || "").toLowerCase(); if (c.indexOf("netherland") !== -1 || c.indexOf("nederland") !== -1) return km.toFixed(1) + " km"; return (km * 0.621371).toFixed(1) + " mi"; }; const shortAddr = (v) => { if (!v) return ""; const parts = v.split(",").map((s) => s.trim()).filter(Boolean); if (parts.length <= 2) return parts.join(", "); return parts[0] + ", " + parts[parts.length - 1]; }; const selectedCount = () => { let n = 0; st.competitors.forEach((c) => { if (c.sel) n++; }); return n; }; const styleRow = (row, sel) => { row.style.cssText = "display:flex;align-items:center;gap:13px;border:1.5px solid " + (sel ? "#F59273" : "#e7e9ee") + ";border-radius:13px;padding:12px 14px;cursor:pointer;text-align:left;background:" + (sel ? "#fff7f3" : "#fff"); const chk = row.querySelector(".xws-check"); chk.style.cssText = "width:24px;height:24px;border-radius:7px;flex:none;display:flex;align-items:center;justify-content:center;color:#fff;font-size:14px;font-weight:700;border:2px solid " + (sel ? "#F59273" : "#d7dbe2") + ";background:" + (sel ? "#F59273" : "transparent"); chk.textContent = sel ? "\u2713" : ""; }; const renderList = () => { const list = byId("xws-list"); list.innerHTML = ""; const tpl = byId("xws-row-tpl"); st.competitors.forEach((c, i) => { const row = tpl.cloneNode(true); row.removeAttribute("id"); styleRow(row, c.sel); row.querySelector(".xws-cname").textContent = c.name || ""; const vic = row.querySelector(".xws-vic"); const va = shortAddr(c.vicinity); if (va) { vic.textContent = va; vic.style.display = ""; } else { vic.style.display = "none"; } const rt = row.querySelector(".xws-rating"); if (c.rating != null) { rt.textContent = "\u2605 " + Number(c.rating).toFixed(1); rt.style.display = ""; } else { rt.style.display = "none"; } const metaParts = []; const dist = fmtDist(c.distance_km); if (dist) metaParts.push(dist); if (c.review_count != null) metaParts.push(c.review_count + " reviews"); row.querySelector(".xws-meta").textContent = metaParts.join(" - "); row.addEventListener("click", () => toggle(i)); list.appendChild(row); }); byId("xws-count").textContent = st.competitors.length + " in de buurt, " + selectedCount() + " geselecteerd"; byId("xws-more").style.display = st.nextToken ? "" : "none"; }; const toggle = (i) => { const c = st.competitors[i]; if (!c) return; if (!c.sel && selectedCount() >= MAX_PICK) { return setMsg("We monitoren maximaal " + MAX_PICK + " concurrenten. Kies je dichtstbijzijnde.", true); } c.sel = !c.sel; setMsg(""); renderList(); }; const fetchCompetitors = async (append) => { const b = st.business; const body = { lat: b.lat, lng: b.lng, category_keyword: b.category_keyword, own_place_id: b.place_id }; if (append && st.nextToken) body.page_token = st.nextToken; try { const r = await fetch(API_BASE + "/api/xw_competitors", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); const d = await r.json(); if (!r.ok || !d || !d.competitors) { return setMsg((d && d.error) || "We konden geen concurrenten laden. Probeer het opnieuw.", true); } const fresh = d.competitors.map((c) => { c.sel = false; return c; }); if (append) { const seen = {}; st.competitors.forEach((c) => { seen[c.place_id] = 1; }); fresh.forEach((c) => { if (!seen[c.place_id]) st.competitors.push(c); }); } else { st.competitors = fresh; st.competitors.forEach((c, i) => { c.sel = i < PRESELECT; }); } st.nextToken = d.next_page_token || null; setMsg(""); renderList(); } catch (e) { setMsg("Er ging iets mis. Probeer het opnieuw.", true); } }; const doContinue = () => { const picks = st.competitors.filter((c) => c.sel); if (picks.length === 0) { return setMsg("Selecteer minstens één concurrent om te volgen.", true); } try { sessionStorage.setItem("xw_selected", JSON.stringify(picks.map((c) => ({ place_id: c.place_id, name: c.name, address: c.vicinity != null ? c.vicinity : null, distance_km: c.distance_km != null ? c.distance_km : null, rating: c.rating != null ? c.rating : null, review_count: c.review_count != null ? c.review_count : null })))); } catch (e) {} window.location.href = NEXT; }; byId("xws-more").addEventListener("click", () => fetchCompetitors(true)); byId("xws-continue").addEventListener("click", doContinue); byId("xws-list").innerHTML = ""; setMsg("We zoeken je concurrenten..."); fetchCompetitors(false); }); })();

.


Uw Email

Geef je e-mail op om je gratis maand te starten. We volgen je concurrenten en je hoort elke week wat er bij ze is verandert .

(() => { function ready(fn) { if (document.readyState !== "loading") { fn(); } else { document.addEventListener("DOMContentLoaded", fn); } } ready(() => { const root = document.getElementById("xwe-app"); if (!root) return; const API_BASE = "https://mapalert-places-api.vercel.app"; const CHECKOUT = root.getAttribute("data-checkout") || "/#scan"; const byId = (id) => document.getElementById(id); const setMsg = (t, isErr) => { const m = byId("xwe-msg"); m.textContent = t || ""; m.style.color = isErr ? "#c0392b" : "#8a93a0"; }; let busy = false; const submit = async () => { if (busy) return; const email = byId("xwe-email").value.trim(); if (!email) { return setMsg("Vul je e-mailadres in.", true); } let business = null; let picks = []; try { business = JSON.parse(sessionStorage.getItem("xw_business") || "null"); picks = JSON.parse(sessionStorage.getItem("xw_selected") || "[]"); } catch (e) {} if (!business || !business.place_id || !picks.length) { return setMsg("Je selectie is verlopen. Begin opnieuw.", true); } busy = true; setMsg("We zetten alles klaar..."); try { const r = await fetch(API_BASE + "/api/xw_website-lead", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: email, place_id: business.place_id, business_name: business.name || null, address_line1: business.address_line1 || null, address_line2: business.address_line2 || null, address_city: business.address_city || null, address_postal_code: business.address_postal_code || null, address_country: business.address_country || business.country_code || null, rating: business.rating != null ? business.rating : null, review_count: business.review_count != null ? business.review_count : null, maps_url: business.maps_url || null, category_keyword: business.category_keyword || null, category_display: business.category_display || null, product: "hairalert", competitors: picks }) }); let d = null; try { d = await r.json(); } catch (e) { d = null; } busy = false; if (!r.ok) { return setMsg((d && d.error) || "We konden je scan niet starten. Probeer het opnieuw.", true); } try { sessionStorage.setItem("ma_place_id", business.place_id); sessionStorage.setItem("xw_email", email); } catch (e) {} window.location.href = CHECKOUT; } catch (e) { busy = false; setMsg("Er ging iets mis. Probeer het opnieuw.", true); } }; byId("xwe-btn").addEventListener("click", submit); }); })();

.


Bedankt!

We beginnen je concurrenten te monitoren. Hun websites, hun sociale media accounts en hun profielen op Google Maps.

.

Live Monitoring

Alles wat we vinden wordt gebundeld tot één compact rapport. Afgestemd op jouw regio en rechtstreeks in je inbox bezorgd. Direct klaar om te lezen, elke week weer.

.

HairAlert

Jij richt je op je klanten, wij op je concurrenten. Wees als eerste op de hoogte met je eigen lokale concurrentierapport.

Nu voor slechts €39 per maand!