Every dashboard feature, explained in full.
Not a FAQ — a full reference. Every group in your dashboard sidebar, the ISN website itself, and the guest captive portal your visitors actually see, each explained field by field, screen by screen. If you want the short version of common questions instead, see our Help Center.
Jump to a section
Documentation covers three layers: your dashboard, organized exactly like its sidebar — Overview, Clients, Branding, Messaging, Billing & plan, Vouchers, Free access, Network, Insights, Team & access, and Account — plus the ISN website itself and the guest captive portal your visitors actually see. On a wider screen, use the sidebar on the left to jump straight to any single item without scrolling.
Overview
The landing view every dashboard session opens on — a live rollup of the same numbers that drive your bill and your capacity limit, so you never have to dig for them.
Dashboard home
Your "at a glance" screen. Portal state reads "Portal live" once you've clicked Publish, or "Setup in progress" before then — this is a confirmation flag you control, not an access gate: your captive is reachable to real guests the moment a router points at it, published or not. Domain shows your active address (free subdomain or verified custom domain). Active now is a genuinely live count, computed fresh every time the page loads — it's not the same thing as This month's peak / limit next to it, which is your real high-water mark for the current calendar month (the number your bill is actually based on) and can easily read higher than "Active now" if your busiest moment already passed, or lower right after a new month starts and nobody's connected yet. Both, plus Estimated monthly cost, are detailed further under Plan & pricing below. SMS credits, Routers online, Vouchers redeemed (7d), and Ad views (7d) round out the top row, followed by a 7-day guest-traffic chart, a 7-day peak-concurrent-devices chart, and a router fleet table (name, location, online status, device count, last seen) — empty until you add your first router under Network → Routers.
Onboarding checklist
A small 4-step panel at the very top of this page — add a router, upload your logo, set up at least one way to earn (ads, vouchers, or data plans), and publish — each ticking off automatically the moment you actually complete it elsewhere in the dashboard, not something you check off by hand. Every step is re-checked live each time this page loads rather than remembered as a one-time flag, so it's a genuine "what's left right now" view, not just a first-run tour — the panel hides itself once all four are true and reappears if one later becomes untrue again (e.g. you remove your only router or unpublish). Exists specifically to catch the case where a tenant signs up, hits some unrelated hiccup, and never quite finishes setup, before that drift goes unnoticed.
Portal preview
The real thing, not a mockup — this loads your actual live captive portal, with your real logo, colors, and brand name, inside the dashboard so you can check it without leaving. Save a change under Branding & colors and this refreshes automatically. An "Open in new tab" link sits next to it for when you'd rather test on a full screen or a phone.
Post ads & more ↗
This ISN Portal — everything documented on this page: your account, branding, billing, vouchers, network, and team — lives at https://isnfreewifi.co.za/dashboard, reached by logging in at https://isnfreewifi.co.za/login with your ISN Free WiFi email and password. That is a completely different address and a completely different dashboard from your own captive's own domain — a second, separate dashboard lives THERE instead, reachable at your live captive address with /dashboard on the end (e.g. https://yourbrand.isnfreewifi.co.za/dashboard, note it's on YOUR domain, not isnfreewifi.co.za) — that one is only for ad campaigns, ad-performance tracking, and a few captive-specific tools (see Captive Dashboard below); it does not have vouchers, billing, branding, or any of the settings documented on this page. "Post ads & more" opens that second one for you in a new tab, already pointed at your own captive, using the exact same email and password you use here — no separate login to remember. It stays visible the moment your account exists, whether or not you've published yet.
Clients
Built for agencies, resellers, and ISPs running WiFi for more than one site under one login.
My clients
Every branded location tied to your account — name, domain, publish status, router count, revenue (last 30 days), and alerts — all reachable without a second login. Each client is a fully separate, isolated captive: its own branding, its own routers, its own vouchers, its own guest data. Nothing about one client's setup or guest list is visible from another. Revenue and alerts are a genuine franchise-style rollup, not per-client links you have to click through: revenue sums the same ad/voucher/data-plan totals shown on each client's own Analytics & reports, and alerts counts routers currently offline for that client, so an owner running several branches can see at a glance which one needs attention without switching into each site. Add a new one with just a business name (no separate email/password — you're already verified); one click on any row in the table switches your whole dashboard session into that client, the same mechanism as Switch captive. One limit worth knowing: an account that has never made a real subscription payment is capped at 2 captives total, so a free/trial account can't be used to spin up unlimited draft portals — the cap lifts permanently the moment any one of your captives completes its first real payment.
Branding
What your guests see, and the address they see it at.
Branding & colors
Everything that makes your captive portal look like your business instead of a generic template: brand name, short name, logo upload, four colors (primary, accent, background, text), tagline and summary copy, your login page's own description and "how it works" steps, support email and WhatsApp number, Facebook/Instagram/TikTok links (any left blank simply don't show — nothing appears by default), and your own terms-of-service text (falls back to ISN's default if you leave it blank). A live phone-mockup preview sits alongside the form on tablet and desktop, with Login/Home/Business tabs, updating as you type — on phones this becomes a "Preview" button that opens the real portal in a new tab instead, since a side-by-side mockup doesn't fit usefully on a small screen. Changes apply immediately on save; there's no separate publish step for branding itself. Everything you set here is exactly what loads on the real guest screens documented under The captive portal further down this page — Captive Login, Home, and Marketing Page all pull their logo, colors, and copy from this one place.
Custom domain
Every account starts with a free working address the moment you sign up — you can be live before you ever touch this section. Add your own domain when you're ready and guests never see ours again. Type the domain you own (e.g. yourbusiness.com, no "www." or "captive." needed) and ISN sets up captive.yourbusiness.com as your guests' WiFi login page — the rest of your domain, your website, your email, is completely untouched. You'll then get one DNS record to add at your domain provider: a CNAME (or, if your provider can't do CNAME on a subdomain, a fallback A record). Verification is a real, live DNS lookup against exactly that captive. subdomain — never your bare root domain, never "www" — so it only goes active once it's genuinely resolving correctly, not a box you get to tick yourself. Your router's own External Login URL updates automatically to your new domain once verified — but that's only what the dashboard shows a NEW router going forward; any router you already configured keeps using whatever address was pasted into its own Hotspot settings at the time, since verifying doesn't reach out and change anything on hardware. Once verified, an "Update your routers to the new address" button appears right on this page — one click (password-confirmed) re-pushes the new address to every OpenWRT/Teltonika/GL.iNet router you own automatically; a MikroTik or other-vendor router has no automated push for this setting and needs its Hotspot URL changed by hand, or via Remote CLI one at a time. The old free-subdomain address never stops working, even after your custom domain is verified — there's no rush, and nothing breaks for a router you haven't gotten to yet. Keep your free subdomain active until your custom domain is verified — turning it off any earlier takes your portal offline for anyone still using the old address.
Messaging
SMS is built into the platform itself for guest and account verification codes and account notifications — there's no separate provider or API key for you to configure. Every one-time code sent, to a guest or to your own team, uses one credit from your balance.
SMS balance
Your current credit balance, front and center. A banner appears once you hit zero credits, since that's the point OTP codes stop sending to guests trying to sign up or verify a new device — the exact verification step described under Captive Login below.
Daily sending limit. Every tenant sends through the SAME shared SMS provider account, whose own daily quota is a fixed pool — a per-tenant ceiling (200/day by default) stops one tenant's send burst from starving every other tenant's messages for the rest of the day. This never affects sign-up/login/password-reset codes, which always go through regardless of how much of today's limit marketing or notification texts (re-engagement, win-back, low-data nudges) have already used — only those non-urgent sends are capped, since a guest waiting on a real code right now is a much worse thing to block than a delayed reminder text. If you have a genuine need for a higher limit, email ISN Free WiFi to request one raised for your account specifically.
Buy credits
Type either a Rand amount or a number of credits — the other side calculates itself automatically, so you never have to do the conversion by hand. Pay by card (instant) or by EFT (you'll get banking details; credits land once payment is confirmed). Minimum purchase is 200 credits.
Two settings live alongside this, under Notifications: "Alert me at (credits)" sends you a low-balance email once your balance drops to a threshold you set. Auto top-up optionally buys more automatically the moment that threshold is hit — instantly on a saved card if you have one on file (from a trial or subscription payment), or as a pending EFT request if you don't. "Do not exceed this spend per month (R)" is the safety net on auto top-up specifically: once your automatic top-ups for the calendar month reach that Rand figure, auto top-up pauses itself (you still get the low-balance email, and can always top up manually) rather than continuing to spend without limit. That cap resets at midnight South African time on the 1st of every month.
Credit history
Every credit purchase you've made — manual card, manual EFT, or auto top-up — with date, amount, credits, and status. Each settled purchase generates a proper invoice with a PDF receipt emailed to you automatically, the same invoicing your subscription billing uses, so SMS spend is tracked exactly as accountably as everything else you're billed for.
Sent messages
The full send log — every OTP and notification actually sent, filterable by status (delivered, failed, and so on), so you can see exactly where your credits are going and confirm a specific guest's code really did go out. A Credits column shows exactly how many credits each individual send was actually charged — see How SMS credits are calculated just below for why that number isn't always 1.
How SMS credits are calculated
A short message costs 1 credit, same as ever — but a longer one can cost more, because that's genuinely how SMS itself works under the hood: a message beyond a certain length doesn't fit in one real SMS, so it's split into multiple, and each one is billed as its own message by our own SMS provider. This platform now charges your credit balance to match exactly what we're actually billed for your message, rather than a flat 1 credit regardless of length.
Plain-text messages (letters, numbers, and standard punctuation) fit 160 characters in a single credit. Go over that, and the message splits into multiple parts of 153 characters each — so, for example, a 250-character message needs 2 parts (2 credits), and a 400-character one needs 3 (3 credits). Most OTP codes and short notifications comfortably stay under 160 characters and will always cost exactly 1 credit; a longer message — a link-heavy invite, a detailed reminder — is the kind that can cross that line.
Messages using emoji, accented characters, or a non-Latin script (á, ü, —, 😊, or any script outside the basic Latin alphabet) are sent in a different format that fits far fewer characters per part — 70 characters for a single credit, or 67 per part once split. This isn't specific to this platform; it's how SMS itself is encoded worldwide, the same reason a text with a single emoji in it can suddenly "use up" far more of your character count than you'd expect. If you're writing your own custom message templates and want to keep costs predictable, sticking to plain ASCII characters (no emoji, no smart/curly quotes or em dashes, no accented letters) keeps you in the cheaper 160/153-character tier.
This applies uniformly to every SMS this platform sends on your behalf — OTPs, password resets, partner invites, re-engagement and win-back campaigns, low-data nudges — there's no separate pricing for any particular message type; it's always about the actual length and character set of what's being sent.
Maximum length: 3 parts. A message needing more than 3 parts — over 459 plain-text characters, or over 201 with emoji/accented characters/non-Latin script — is rejected outright before anything is sent or any credit is charged, rather than being sent anyway at a higher cost. If you're writing a long custom message (a detailed reminder, a link-heavy invite) and it's close to this limit, shortening it is the only option; there's no way to pay more to send a longer single SMS.
Email settings
Connect your own sender so invites, password resets, and ad-campaign notifications sent to the businesses/advertisers on your platform come from you, not a shared ISN address. Two options, and you can connect either one or both: SMTP — your own email address and password (Gmail/Google Workspace app-password by default; open "Advanced" to point at a different provider's mail server, host/port/SSL) — or a Resend API key, for a tenant who already runs their product's email through Resend and would rather not manage a separate mailbox password. Either way, add an optional display name and Save & verify — for a Resend key, verifying sends a real test email to your own account address to confirm the key and "from" address actually work together. For your own security, once saved a password or API key can never be viewed again in the dashboard — only replaced with a new one or removed entirely. Only the account owner or an "IT" team role can configure this. This is also the address your Marketing Page advertiser-inquiry form emails to, once set.
Connected both? A send tries Resend first, then your SMTP sender, then falls back to the default ISN address only if both are unavailable — so pairing them gives you a real backup instead of a single point of failure. If you're setting up Resend, create a key scoped to "Sending access only" rather than full access — this platform only ever needs to send email, never to read your domains, logs, or account settings, so a restricted key limits what could be done with it if it were ever exposed. The "from" address you enter also has to be on a domain you've already verified in your own Resend account, or sending will fail.
If a connected sender stops working — a password changes on your provider's side, a mailbox gets suspended, a Resend key gets revoked — nothing you rely on it for silently stops arriving. Every email that would have gone through it automatically falls back down the chain above (or to the default ISN sender if nothing else is connected), still shown under your own brand name, so an invite, a notification, or a sign-in code always gets through one way or another. You won't be locked out of your own dashboard by a sender problem you haven't noticed yet.
Daily sending limit — only on the default ISN sender. If you haven't connected your own SMTP or Resend account above, your email sends through ISN's own shared sender, which carries a fair-use daily ceiling (50/day by default) so one tenant's volume can't affect deliverability for everyone else on it. The moment you connect your own sender here, that limit no longer applies to you at all — you're sending through your own account, not the shared one. Either way, sign-in codes, password resets, account verification, team invites, and your own invoices/receipts always go through regardless of this limit; only routine notification email (ad/survey milestones, router and capacity alerts) is affected.
Billing & plan
Your own subscription for running this captive on ISN Free WiFi — a 14-day free trial (one per account, card-verified up front), then billed monthly.
Subscription
Status, your next trial/billing date, and the card on file, plus controls to update your payment method, suspend your captive (unpublish — takes your guest-facing URL offline immediately without cancelling the subscription itself; republish any time before your next billing date at no extra cost), or cancel outright. Miss a payment and you get a 5-day grace period: your dashboard flags the account as past due, but your captive keeps serving guests normally throughout. Only if the balance stays unsettled past those 5 days do portal-facing features get suspended — nothing is ever deleted, your configuration and history stay exactly as they were.
Starting a trial, paying immediately, or updating your saved card all run a small R5 charge first, purely to confirm the card is real. Our payment processor doesn't support automatically refunding this charge, so instead of a refund you're credited 10 free SMS credits (worth R5, at the standard R0.50/credit rate — see Messaging) the moment verification completes — real value back either way, just not as a literal refund.
That "no extra cost" republish window has a limit, though: it only applies while you're still within the cycle you already paid for. Wait until your next billing date has actually passed while unpublished, and republishing charges the current monthly rate immediately, right before your captive goes back live — the billing job deliberately never charges an unpublished tenant on its own, so that dark time was never billed for, but it's also never free to skip once you're ready to come back. Cancel outright is different again from either of those: it clears your billing date and any trial, takes your portal offline immediately, and stops every future charge for good — no more billing runs at all until you actively resubscribe. Either way, your saved card stays on file, so resubscribing later (or republishing after a lapse) never needs a fresh R5 verification charge.
One more thing tied to payment status rather than plan: a brand-new owner account that has never completed a real subscription charge on any of its captives is capped at 2 captives total — an anti-abuse limit on spinning up endless unpaid drafts, not a feature restriction. It lifts for good the moment your first real payment goes through (trial-conversion or an immediate charge both count), no matter which captive paid, and every captive you create afterward — on that account — is unlimited.
Plan & pricing
R1,500/month includes 300 concurrent users, with unlimited routers and locations at no extra cost — extra concurrent users beyond 300 bill at R5/user. This is the same plan described on the public Pricing page; nothing changes between what's quoted there and what you're billed here. "Concurrent user limit" is purely an access gate — the ceiling you set (or that auto-scale raised for you) that decides when a new guest gets turned away, nothing more. It never affects your bill by itself: raising it to leave yourself headroom costs nothing extra unless guests actually fill it. What you're billed on is "Peak concurrent users this month" alone — your real high-water mark for the current calendar month, tracked continuously as guests actually connect — compared against the 300 included in your plan. That also means lowering your limit after a busy period doesn't retroactively lower what you're billed for the users you genuinely had that month; it only affects what happens going forward. Auto-scale when at capacity, if switched on, raises your limit automatically by a fixed increment every time it's reached, instead of turning new guests away — configure the increment and an optional ceiling ("never auto-scale above") separately. A limit auto-scale raised can't be lowered below that point until the next billing month, but a limit you set yourself here stays exactly as you left it. Capacity monitoring is a separate early-warning email, sent once usage crosses a percentage you choose — before anyone is actually turned away, distinct from the "at capacity" notification that fires once the real limit is hit.
Why is my bill this amount?
A "Why is my bill this amount?" panel sits right under Plan & pricing, collapsed by default — it walks through the exact same formula in plain numbers: base price, how many concurrent users are included, your actual peak this month, how far over the included amount that peak went, and the per-extra-user rate, ending in the same total shown above it. Below that, a "Peak per month" table lists your peak concurrent users for each of your last several billing months, for context. Worth knowing the limit here: this platform records each month's peak number only, not which day or hour within that month produced it — so this answers "what number am I billed on and how was it calculated," not "what time of day was busiest," which isn't tracked at this granularity today.
Invoices
Every charge against your own subscription — invoice number, date, amount, status. Only ever your own; never visible across tenants.
My revenue
What you've actually earned, in one place — separate from what you owe us in Plan & pricing. Three totals, each for the date range you pick: ad revenue (what advertisers paid for views delivered on your captive, capped at each campaign's own budget — see Ad pricing), voucher revenue (the price you set on every voucher actually redeemed — see Generate vouchers), and data plan revenue (card payments guests made for a Data plan). A daily trend chart breaks all three down together, and "Download statement (PDF)" generates a one-page summary for any calendar month — revenue earned alongside your subscription cost for that month, and the net of the two — for your own bookkeeping.
Every rand shown here is 100% yours — ISN never takes a share of ad, voucher, or data plan revenue. Your only cost on this platform is the flat subscription in Plan & pricing; what guests and advertisers pay is a separate transaction that never routes through an ISN-controlled account in the first place. Card payments for data plans, and prepaid 1Voucher/OTT redemptions, settle straight into your own Paystack, PayFast, or Flash Group merchant account (see Payment gateways) — we only ever check that a payment happened, we never touch the money itself. Vouchers you generate yourself are sold however you choose (cash, front desk, your own booking system); the platform just tracks issuance and redemption, so the full price is whatever you actually collected. Ad campaigns go further still — a local business's spend is only ever tracked here (views delivered × your price, capped at their budget, per Ad pricing) so you know exactly what to bill them; no payment gateway is involved in a campaign at all, so collecting from that advertiser (invoice, EFT, cash — your call) is a matter between you and them alone.
Revenue by router. If you run more than one router or location, a second table below the trend chart breaks ad, voucher, and data-plan revenue out per router instead of one combined total — plus ad views, voucher redemptions, and data plans sold at each one, so you can actually see which locations are underselling and which are carrying the venue. Two independent signals flag a router worth a look: a router earning under half your per-router average for the selected range is Underselling (over 1.5× is Overselling) — that's compared against your OTHER routers right now. Separately, a Trend column compares each router against its OWN prior period of the same length, so a router that used to earn well and just dropped shows up even if it's still above the fleet average. Each router also shows its live online/offline status right alongside its numbers, since a router that's simply been offline explains low revenue on its own. A "Rank by" toggle lets you sort the table by total revenue or by growth — useful for presenting which locations are actually improving, not just which are biggest. (Survey revenue isn't broken out per router yet, and stays in the combined total above only.) The same breakdown, same numbers, is also on the Captive Dashboard's own Billing & Revenue tab.
Revenue by department. A third table rolls the same revenue up by router group instead of by individual router — one row per group with its router count and ad/voucher/data-plan/total revenue, plus an "Ungrouped" row for any router not yet assigned to one. Useful once "per router" is too granular to present — a city reporting Parks routers vs Libraries routers, a franchise reporting by branch — without having to add up individual routers by hand every time. Purely a different view of the same numbers above; assigning routers to groups is done under Router groups, not here.
How you profit — ads, vouchers & data plans
Three separate, combinable income streams sit on top of the WiFi you're already running — none of them require you to build anything, and all three can run at once.
Ads. Local businesses pay to reach your guests — either you sell the campaigns yourself, or (see Captive Dashboard) you add the business its own login and let it build and fund its own campaign against the price you set (Ad pricing). Either way, a guest earns free data by watching, so this is also what funds ad-supported access without charging the guest directly — you get paid by the advertiser, the guest gets online for free.
Vouchers — internal and external, and the difference between them. "Internal" vouchers (Generate vouchers) are codes you create, price, and hand out yourself — cash at the front desk, bundled into a room rate, sold through your own booking system, whatever fits your venue; the platform only tracks issuance and redemption, so the price is entirely yours to set and collect. "External" vouchers (1Voucher & OTT Voucher) run the other way around: they're real prepaid PINs a guest already bought elsewhere — a spaza shop, a supermarket till, their own banking app — with nothing to do with you until they redeem it on your portal. You still profit from these, just differently: you set the bundle/price menu they're redeemed against (External voucher bundles), and the guest's full PIN value is credited to their balance and spent against your pricing, settling into your own connected Flash merchant account (Payment gateways) — useful specifically for guests with cash but no card and no data to pay you online.
Data plans. The most direct of the three — a guest pays by card for a plan you priced (Data plans), no voucher or ad-watch involved, settling straight into your own connected card gateway. The same bundle list doubles as what an external-voucher balance buys, so you only ever maintain one price menu for both.
None of this is mutually exclusive with giving guests free access too — ad-supported bundles, your own generated vouchers, external voucher redemption, and direct card sales can all be switched on at the same time (Generate vouchers), and a guest simply sees whichever combination you've turned on. See My revenue for how all three are reported, and why none of it is shared with ISN.
Payment gateways
Where you connect the account that actually settles real money from guests — card payments for Data plans, and/or the prepaid voucher PINs covered in 1Voucher & OTT Voucher just below. Pick a Provider, fill in its fields, and click "Connect & verify" — the key is checked live against the provider before it's saved, so a typo or an expired key is caught immediately rather than failing silently on a guest's first real payment. For your security, once saved a key can never be viewed again here, only replaced (paste a new one) or removed — keep your own copy somewhere safe if you'll need it again. Only the account owner can connect or remove a gateway.
Paystack (card payments): paste your Secret API key; a Public API key is optional but recommended. Without a public key, a guest paying for a data plan is sent to Paystack's own hosted payment page to pay — still fully secure, just an extra hop. With one, they pay in a popup right on your portal without ever leaving the page, and their card number goes straight into Paystack's own secure popup, never through your server or ours. Paystack only comes into play once "Sell data plans directly by card" is switched on under Generate vouchers (only offered when ad-supported bundles and voucher redemption are both switched off).
PayFast (card payments) is one of two alternatives to Paystack (see Yoco below for the other) — connecting any one of the three replaces whichever was previously connected as your card option; a portal uses exactly one card gateway at a time, never more. A guest paying for a data plan is always sent to PayFast's own hosted payment page (there's no in-page popup option, unlike Paystack's optional Public key). To connect it correctly, in order:
- In your own PayFast account, go to Settings → Developer Settings and copy your Merchant ID and Merchant Key into the matching fields here.
- Under Settings → Security Settings, set a Security Passphrase — required, not optional, even though PayFast's own UI calls it optional; payments can't be verified without one, so paste the exact same passphrase into the field here too.
- Under Settings → Notifications Settings, set the Notify URL to the address shown once you pick PayFast here (click Copy, then paste it into PayFast), and make sure ITN Status is Enabled. This step is the one most likely to be missed, and the one that actually grants a guest their data plan — PayFast still takes the guest's payment either way, but without a correct Notify URL this portal is never told the payment happened, so the guest is charged and gets no internet access. If that happens, the guest's purchase stays stuck on "pending" instead of turning into access — that's the sign this step needs redoing.
- Click Connect & verify. Unlike Paystack, PayFast has no way to check these details are correct up front, so this only saves them — the real confirmation is a small real payment once you're set up, checked all the way through to a guest actually getting online.
1Voucher and OTT Voucher (prepaid PINs, both issued by Flash Group): see 1Voucher & OTT Voucher for what these look like to a guest. To connect either, you'll need a Flash API key, a merchant account number, and an Environment (Sandbox for testing, Production once you're ready to accept real vouchers) — obtained by applying as a Flash integration partner (contact integrations@flash.co.za). The two are connected separately since each has its own merchant account number, but if you're already a Flash partner for one, the same API key usually works for the other too. You can connect one, both, or neither independently — whichever you have connected is what shows up as a redeem option on your captive portal.
Yoco (card payments, new) is the third card option alongside Paystack/PayFast — same "exactly one at a time" rule. Paste your Secret key (Yoco Dashboard → Online → API Keys) and a Webhook secret (Yoco Dashboard → Online → Webhooks — add a webhook pointed at the URL shown here once connected, and paste the secret it gives you). A guest paying for a data plan is sent to Yoco's own hosted checkout page. Without the webhook secret configured on both sides, Yoco still takes the guest's payment but this portal is never told it happened — same failure mode, and same fix, as a missing PayFast Notify URL above.
SnapScan and Zapper (new) are a different kind of payment entirely — QR-code, not card. A guest sees a QR code right on the captive portal and scans it with their own SnapScan or Zapper app to pay directly; no card details ever touch this portal. Both can run alongside a card gateway and alongside each other (like 1Voucher/OTT above, not like the mutually-exclusive card gateways). For SnapScan, paste your API key and SnapCode from your Merchant Portal, plus a Webhook Auth Key (also from the Merchant Portal, under Developer settings) — without it, SnapScan still takes the payment but this portal is never told. For Zapper, paste your Merchant ID and Site ID, then paste the notification URL shown here (once connected) into your Zapper Merchant Portal's webhook settings — this is what actually confirms a payment happened. Both are newly built and not yet verified against a real SnapScan or Zapper account.
Partners
Split a router's revenue with whoever actually hosts it — a taxi driver, a fleet owner with many vehicles, or a venue you don't run yourself. This is a different relationship from a team member (who works for you) or an advertiser on the Captive Dashboard (who pays you) — a partner earns a cut of what their own router brings in. Managed entirely on the Captive Dashboard's own Partners tab, reachable the same way as Post ads & more, and restricted to the Admin/IT team roles (see Team members).
What is a Partner?
A Partner is a record tied to your tenant, not a login on its own — it becomes a real account only once they set a password via their invite (see Adding a partner). One router belongs to at most one partner at a time, kept deliberately simple: revenue from a router is never split between two different partners. A partner can own as many routers as you assign them, and their earnings across all of them are combined on their own dashboard.
This is built directly on the same per-router revenue engine behind My revenue's "Revenue by router" table — a partner's cut is always a percentage of the exact same ad, voucher, and data-plan revenue you already see for that router, never a second, separate calculation that could drift from it.
Partner groups & split percentage
Create a named group once — for example "Standard Drivers: 20%" or "Fleet Owners: 25%" — with a default split percentage, then add partners into it instead of setting a rate on every single one individually. A specific partner can also get their own override percentage on top of their group, for a one-off deal that doesn't fit the group's standard rate; their dashboard shows plainly whether their rate comes from their group or is a custom override.
Editing a group's percentage is immediate and retroactive for that group's members — there's no rate-history timeline, so changing "Standard Drivers" from 20% to 22% changes it for every partner currently in that group, both for revenue going forward and for how their past earnings display from that point on. If you want existing members to keep the rate they signed up under, leave that group alone and create a new group for future partners instead — two groups is the normal way to handle a rate change, not a special flag on the old one.
Adding a partner
Click Add Partner, give a name, a phone number and/or an email (at least one is required), optionally a group and/or an override percentage, and pick which router(s) they host. Revenue tracking for those routers starts the instant you save — a partner's earnings never wait on them logging in, so cash you agreed to share starts accumulating correctly from day one even if they don't set a password for weeks.
Every router you pick is checked against your own tenant and against every OTHER partner's current assignments before saving — a router already assigned elsewhere can't silently be reassigned out from under someone, and two admins racing to assign the same router at the same moment can't both succeed (whoever's request lands first wins; the other gets a clear "already assigned" error instead of silently corrupting the split).
Phone-only partners (the common case for a driver) are fully supported — leave email blank and just give a phone number, in whatever format you have it (+27..., 0..., spaced out). It's normalized to one consistent form behind the scenes, so a partner searched, displayed, or logging in under a slightly different-looking version of the same number is always recognized as the same person, never treated as a duplicate or a stranger.
The All Partners table is searchable (by name, phone, or email — including across those same phone-format variants) and paginated, so it stays fast and usable whether you have three partners or a fleet of thousands. Click View on any partner for their own revenue chart and per-router breakdown in a modal, without leaving the list.
The partner's own dashboard
A partner logs in at the exact same address and login form as everyone else on your Captive Dashboard — the platform recognizes their account's role and shows them a completely different, restricted experience automatically, never the tabs an advertiser or your own team sees. Their side panel has exactly five items:
- Overview — combined earnings across every router they host, broken into Today / This week / This month / Lifetime, plus their current status (Pending setup, Active, or Ended).
- My Routers — each router they currently host, its live online/offline status, how many devices are connected right now, its earnings for the last 30 days, and a driver link for that router (see Driver links below).
- Earnings — a 30-day trend chart plus a per-router gross-revenue-vs-their-cut breakdown table.
- My Rate — their current split percentage, and whether it comes from their group or a custom override.
- Settings — just their own password, and an Active Sessions list to sign out a device they don't recognize. Nothing about your business, your other partners, or your other advertisers is ever visible from here.
Some partners are also given a News tab, showing the same read-only announcements feed your other accounts see — useful if you want to keep drivers or venue partners in the loop on changes without a separate channel.
Driver links
A partner often isn't the one physically with a router day to day — a taxi fleet owner has drivers, a multi-site venue has front-of-house staff. Rather than creating each of them a full Partner login, a partner can generate a driver link (and matching QR code) for any router they currently host, straight from My Routers → Get link. No account, no password — whoever the link is given to just opens it.
The link shows today's ad views and that partner's own earnings for that one router only — the same split percentage math their own Earnings tab already uses — never the venue's full gross revenue, and never anything about any other router. It's branded to your captive (your logo, colors, and support contact) and opens at your own domain, e.g. https://yourbrand.isnfreewifi.co.za/driver/<code> — visiting it on a different captive's domain, or with a wrong/mistyped code, shows a plain 403 page instead of ever loading.
Only one link is active per router at a time, and generating a new one (or hitting Revoke) immediately breaks any previously shared link/QR code — useful if a phone with the link on it is lost, or a driver leaves. Because the router has to currently be assigned to THAT partner, one partner can never generate a link for another partner's router.
Invite channel & notifications
A new partner gets an invite link the moment they're added — by SMS, email, or both, whichever you've picked as your tenant's default under Partners → Notification settings (most drivers have no email, so SMS-only is a common choice; a venue-type partner might prefer email). The link opens the exact same in-dashboard "set your password" screen used when you add a business advertiser — fully branded to your own captive, never a separate ISN-branded page — and works whether or not the partner has ever logged in before.
If an invite expires, gets lost, or was never received, a Resend invite button on that partner's row (shown while their status is still Pending) sends a fresh one without recreating the partner or losing any revenue already tracked for them.
Deliberately not spammy day to day — a partner isn't notified on every single ad view or voucher redemption, only when meaningfully cut off (see below), so the channel setting mainly governs invites rather than ongoing chatter.
Cutting off a partner
Click Cut off on a partner to end the arrangement. Every router they hosted immediately reverts to earning 100% for you — nothing routes to them from that moment on — until you manually reassign that router to someone else. Their login isn't revoked: a cut-off partner can still sign in and see their own full historical earnings and rate exactly as they always could, which matters if the arrangement is ever disputed later. You can also view a cut-off partner's history from the admin side at any time, and their revenue keeps showing correctly in the Billing tab's historical figures — cutting someone off doesn't erase what already happened, only what happens next.
Partner Payouts
A single figure — on both the Captive Dashboard's Billing tab and this ISN Portal's own My revenue tab — showing what you currently owe out across every partner (excluding any already cut off) for whichever date range you have selected. It's computed server-side from the same per-router revenue everything else on this page uses, so it can never quietly drift out of sync with what a partner's own dashboard shows them.
Shown for context only — never subtracted from Total earned or Net. Exactly like the ad/voucher/data-plan totals it's built from, ISN is never a party to what you actually pay a partner; this number just tells you what you'd owe if you settled up today. How and when you actually pay each partner (cash, EFT, however you already run that side of the relationship) is between you and them.
Vouchers
Codes and plans your guests redeem or buy directly on the captive portal — you decide how they're sold (cash, front desk, your own booking system), the platform just tracks issuance and redemption. You create and manage every voucher right here, in this ISN Portal at https://isnfreewifi.co.za/dashboard (log in at https://isnfreewifi.co.za/login) — not on your captive's own subdomain (yourbrand.isnfreewifi.co.za/dashboard), which is a separate, ads-only dashboard with no voucher tools of its own (see Post ads & more).
Generate vouchers
Print or hand out a batch of one-off codes. Set how many to generate, the data bundle (MB), duration (in hours, or in days if that's easier — the days field just converts for you), a price for your own records, a batch label, an optional expiry, and max redemptions per code (1 by default for single-use; set higher for a shared code, like a 10-use event code). "Allow adding extra devices" makes a multi-redemption code share one data pool across devices instead of granting a separate bundle each time. Newly generated codes are shown once, with a CSV download — copy them down immediately, since every code's live status stays visible afterward under All vouchers regardless. Three toggles above this section control what end users actually see on the connect screen (Captive Login): ad-supported bundles, voucher redemption, and (once ads and vouchers are both off) direct card-paid data plans — turn on any combination, and at least one of these three must stay on, unless you have a verified 1Voucher or OTT Voucher gateway connected (see Payment gateways), which counts as its own valid way for guests to connect and lets you turn all three of these off — a voucher/external-vouchers-only portal with no ads and no direct card sales is a fully supported setup.
Journey-based pricing. "How is this priced?" can be switched to Journey-based instead of typing a label/price/duration by hand — pick an already-mapped, priced route from Journey presets and choose "One specific stop" (pick the leg, set a quantity, generate that batch — the normal print-shop workflow: repeat per leg as needed) or "All stops" (one full batch per leg in one action, same quantity each). Price and duration come from that route's own per-leg prices either way; label is auto-named from the route and stop. Needs a route with a price on every leg first.
Restricting which router a code can be redeemed on. "Only allow redemption on specific routers" (optional, leave every router unticked for no restriction, the default) is real enforcement, not just a display choice — a guest can only redeem a code from this batch while connected to whichever router(s) you've ticked, checked before the code's use is consumed so a wrong-router attempt never burns it. In Journey-based mode this is inherited automatically from the route's own router restriction (see Journey presets) rather than asking you to set it twice for the same route, so the field only appears in Straight mode.
Voucher presets
Your own reusable pricing menu — e.g. "500MB – R1", "1GB – R1.50" — each with a label, bundle, duration, price, a validity rule (expires N days after issuing, pinned to an exact date set per-voucher, or never expires), max redemptions, and the same "allow extra devices" option as a one-off voucher. This is what makes the API safe to expose to your own systems: a booking or point-of-sale integration references a preset by its ID, and the bundle/price/duration always come from the preset you defined here — never from whatever the calling system happens to send.
Journey-based pricing. Unlike Generate vouchers (a one-off print run, where which stop matters at print time), a preset is a standing template your own systems reference by ID indefinitely — so Journey-based mode here always generates one preset per stop along the route in a single action, rather than asking single-stop-or-all. Your booking system then just references whichever per-stop preset ID matches the fare it's issuing; it doesn't need to separately pass which stop at issue time. The Voucher Presets API can also resolve this dynamically instead, by passing a journey preset ID plus a stop index on a plain (non-journey) preset — useful if you'd rather not pre-generate a preset per leg.
Restricting which router a voucher can be redeemed on. Same real enforcement as Generate vouchers above: "Only allow redemption on specific routers" restricts every voucher issued from this preset — dashboard or API — to the ticked router(s), checked at redemption before the code's use is consumed. Journey-based presets inherit this from the route automatically, so the field only shows in Straight mode.
Journey presets
For an operator running fixed routes — buses, taxis, shuttles — rather than fixed sites: a preset that sizes how long access lasts to an actual trip, not a flat duration. Found under Vouchers → Journey presets. Works across every unlock type this platform has (ads, surveys, data plans, vouchers, and the API) — it's a shared duration override, not a feature bolted onto just one of them.
Two numbers, kept deliberately separate. Trip duration is the real expected travel time. Grace period is extra time added on top, for a big terminal city where the vehicle is still navigating to the actual stop well after entering the city limits — a bus reaching Bloemfontein, for example, isn't at its terminal the moment it crosses into town. Access expires at trip duration + grace period, never before. Keeping these as two fields (rather than one inflated duration number) means the trip-duration figure stays honestly the real travel time, not a padded guess someone has to remember to keep re-padding.
Two ways a guest ends up on one. Without a booking-system integration, this is passenger self-select: your guest-facing portal offers a "which route are you on?" choice alongside the normal ad/survey/voucher/data-plan flow, and whichever preset they pick overrides that flow's usual duration. With the Voucher Presets API, it's fully automatic — your booking system already knows the exact trip at ticket-purchase time, so it passes the journey preset's ID along with the voucher-issue or WiFi-grant call, and the correct duration is baked in with zero passenger input at all.
Optionally restrict a preset to specific routers — useful when different buses run different fixed routes, so a passenger on the Cape Town coach never sees the Durban route as an option. Leave every router unticked for a preset any of your routers can offer. This also closes a real fare-evasion gap, but only when combined with per-stop pricing below: a preset that's BOTH router-restricted AND has per-leg prices keeps a passenger's access working only on that route's own router(s) — buying the cheap short leg then walking onto a pricier bus in the same fleet won't carry that access over. A router-restricted preset with no distance pricing, or a distance-priced preset left open to every router, is untouched by this — ordinary WiFi access (a shop, hotel, or office) always keeps following a guest across your whole fleet exactly as it always has; this narrowing only ever applies to the specific bus-fare case it exists for. Every "restrict to specific routers" checklist on this platform (here, Data plans, External voucher bundles, Generate vouchers, Voucher presets) has a search box and caps what's shown at once — built for a fleet large enough that a flat list of every router would otherwise be unusably long; type a name or router ID to find the one you want, and an already-ticked router stays selected even once it's scrolled out of view by a search.
"Pick the route on a map instead" replaces guessing the trip duration by hand: search for a place by name to jump the map there instead of panning/zooming by hand, then click each real stop along the route in order — first click is where the trip starts, last is where it ends, anything in between is a genuine pickup/drop-off stop (up to 12 total). Each stop also has an optional "wait here" minutes field for a real dwell — a water break, a rest stop, a scheduled layover — that adds to the total on top of driving time. Estimating returns the driving time leg by leg, summed with any wait minutes into a total, drawing the actual road-following direction line on the map so you can confirm it picked the right road, not just a straight line between points. All of this pre-fills the trip duration field above. This is admin-only, one-time setup — it never reads or tracks any guest's location, live or otherwise, and it's a genuinely different thing from Fleet map (which shows where your routers are, not where any person is). Treat the estimate as a starting suggestion, not a guarantee — it doesn't know about real traffic, scheduled stops, or a breakdown, which is exactly what the separate grace period field above is for. Both the search box and the duration estimate need your own free GraphHopper API key, entered once at the top of this page (Journey presets → "Your GraphHopper API key") — sign up at graphhopper.com. This is deliberately your own key rather than one shared across every ISN tenant, so usage and any cost stays yours as your fleet grows, the same way your payment gateway and router-controller keys already work. If no key is saved yet, both the search box and the map button tell you plainly and you can still pan/zoom and enter the duration by hand.
Delayed trips — automatic recovery, if your router reports GPS. A fixed trip duration + grace period can still run out while a bus is genuinely still on the road (traffic, a breakdown, roadworks). If a router is GPS-capable and reporting a live position, and you've saved your GraphHopper key, the platform checks every 5 minutes for a passenger whose access is about to expire on a route with a saved destination, recalculates the real remaining driving time from the router's current position, and extends just that passenger's access to cover it — never open-ended: a single grant can never be extended by more than its own preset's trip duration (so at most double the originally planned time). Whether a specific router supports GPS at all is auto-detected and shown in that router's Manage panel; a router with no GPS hardware simply can't use this, and grace period is still the fallback for it. GraphHopper is a driving-directions calculator, not a live-tracking service on its own — this recovery only works because the router itself reports where it currently is. For a passenger who bought a journey-derived bundle for a specific stop rather than the route's final destination, this recovery recalculates toward THAT stop, not always the last one on the route — so a passenger getting off partway along a delayed route isn't extended based on how long it'll take other passengers to reach the very end.
Per-stop pricing — the piece that actually charges by distance. Once you've clicked out a multi-stop route on the map, each leg between consecutive stops gets its own price field (real fares are rarely a clean per-km formula, so this is admin-typed per leg, not calculated). An optional "Full route discount price" overrides the summed-legs total specifically for a passenger riding all the way to the final stop — leave it blank to just add the legs up. Naming a stop (e.g. "Harrismith") is optional but makes the bundles this generates far more readable than "stop 3". None of this charges anyone by itself — it only becomes a real, buyable product once you generate bundles from it under Data plans' Journey-based pricing.
"Runs roughly from ... to" (departure window) — covers a passenger who arrives early. Set this to roughly when the bus actually departs, and a passenger who buys before that time gets their total access extended to cover the wait too (capped at 3 hours), rather than the clock starting at the moment of purchase and leaving them with nothing while they wait to board — a bored passenger waiting at the terminal can still call home or browse. Leave it blank if the departure time genuinely varies too much to be worth setting; grace period still covers ordinary lateness either way.
Editing a preset, and generating its return trip. "Edit" on any preset reopens everything — stops, per-leg prices, full-route discount, departure window, router restriction — for changes, without needing to delete and recreate it. "Generate return trip" clones an existing mapped route with its stops (and their prices) reversed in one click, since a two-way route is the same physical road run backwards, not a different one to map from scratch — you'll still want to set its own departure window afterward, since an outbound and return trip essentially never run at the same time of day, and it's deliberately left blank on the generated copy rather than guessed.
A relief bus after a breakdown — moving already-paid passengers onto a different vehicle without them losing access — is handled on the replacement router itself, not here: see Routers.
All vouchers
Every voucher you've ever generated or issued via the API, filterable by status (unused, redeemed, void), with code, bundle, duration, price, redemption count, and who redeemed it and when. Downloadable as CSV for your own records.
Print voucher sheet
"Print voucher sheet (PDF)" on All vouchers generates a printable grid of tear-off slips — brand name, code, data amount, duration, price, and expiry if one's set — for a front-desk "sell at the counter" workflow instead of reading codes off a screen. Pulls from your currently unused vouchers, capped at 100 per sheet (already 10 A4 pages at 10 slips a page). Limited to 10 print requests per hour, since each one renders a real PDF server-side rather than just querying data.
Data plans
Sell internet access directly by card — a guest picks a plan on the connect screen and pays with their own card through your connected payment gateway (see Payment gateways). Set a name, price, duration, and data bundle per plan; default is one device per purchase, treated as a standalone guest account, raised per-plan if you want to allow more sharing one purchase. An optional per-plan download/upload speed cap (Mbps) lets a cheaper plan come with a lower speed than a pricier one — see Bandwidth & speed caps for how this sits alongside the platform's other speed limits. This is the exact same bundle list as External voucher bundles further up — a plan added there also shows up here. A plan priced R0 automatically turns on promo protection against repeat claims, and a paid plan can opt into the same protection voluntarily.
Journey-based pricing. "How is this priced?" can be switched to Journey-based instead of typing one name/price/duration by hand — pick an already-mapped, priced route from Journey presets and this generates one bundle automatically for every stop along it (e.g. "Durban → Pietermaritzburg", "Durban → Bloemfontein"), each correctly priced and timed from that route's own per-leg prices and any full-route discount. Every other setting on the form (data cap, device limits, speed caps, fair usage, promo protection) still applies to all of them from the one form. Needs a route set up with a price on every leg first. On the guest's own connect screen these show grouped together under their route's name rather than as a flat list of unrelated-looking bundles — see Home.
Restricting which routers offer a plan. "Only offer this on specific routers" (optional, leave every router unticked to show it everywhere, the same default as today) controls what a guest is even shown, at whichever router they're connected to — useful at a terminal running several different routes from the same building: tick only the Cape Town terminal's router for a "Cape Town → George" bundle, and a guest standing at your Pretoria router never sees a ticket that doesn't depart from where they actually are. This is purely what gets displayed, not a payment gate on its own — it stops a guest from being confused by irrelevant options, it isn't a fare-enforcement mechanism (that's what the router restriction under Journey presets is for). Set at creation, and editable afterward from a "Routers" button on the plan's own row in the list below, without needing to delete and recreate it.
A guest tapping a plan here never actually needs a card at all if they already have a 1Voucher/OTT balance sitting on their account — the portal tries their real balance first, silently, and only falls through to card checkout if that balance genuinely can't cover the price. No "pick a payment method" prompt either way; the guest just taps the plan they want and gets whichever payment path actually applies to them.
Low-data nudge
On by default. Shows a small banner with a "Top up now" button on a guest's screen the moment their active bundle drops below a percentage you set (default 20%), instead of only finding out once access is already cut off. Turn it off, or change the threshold, from the toggle sitting above the Data plans form. Purely a nudge: it never blocks anything and a guest can dismiss it and keep browsing until their data genuinely runs out. Worth knowing its real limit: the banner only exists on the portal page itself, so it can only reach a guest who still has that tab open — once a guest has real internet, nothing routes their ordinary browsing (Google, YouTube, wherever) back through this app, so there's no way to show them anything if they've closed that tab or moved on to another site.
Also text the guest, off by default since it spends your own SMS credits, closes exactly that gap — a text reaches a guest's phone at the same threshold regardless of what they're browsing at the time. Skipped automatically for a guest who only ever gave an email (nothing to text), and the same guest won't be texted again about the same low-data spell within 6 hours, so a guest hovering right at the threshold doesn't get repeatedly messaged.
1Voucher & OTT Voucher
A completely different kind of voucher from everything else on this page — Generate vouchers above is you issuing codes; 1Voucher and OTT Voucher are the reverse: real prepaid PINs a guest already owns, bought with their own cash from somewhere that has nothing to do with you. Both are issued by Flash Group, and both are sold at thousands of everyday spots already — a nearby spaza shop or supermarket till, or straight from their own banking app — so a guest with no card, no data, and no way to get online can still pay for WiFi in cash without you needing a card machine, an online store, or even a data connection for them to reach one.
On your captive portal, a guest types the PIN into the same "Redeem a Voucher" box used for a code your own venue issues directly (see Payment gateways to connect either product first) — there's only one box, and the guest never has to know or choose which kind of code they're holding. Length alone tells the three apart automatically and unambiguously: a venue code is always 8 characters, an OTT Voucher PIN is always 12 digits, a 1Voucher PIN is always 16 digits. A submitted PIN's full rand value is credited straight to a running balance on their account. If it's worth more than a single data plan, the leftover simply stays on their balance to spend on your other plans later — nothing is ever lost to rounding. 1Voucher and OTT Voucher credit the exact same balance, so a guest who has both types on hand can mix and match, and redeeming either only ever adds to that balance — it never auto-spends; the guest still picks which plan to use it on afterwards, the same as if they'd paid by card.
You still need at least one active bundle configured under External voucher bundles — that's the price/bundle menu a redeemed balance actually buys, entirely separate from "Sell data plans directly by card" on Generate vouchers (that toggle only controls whether guests can pay by card without a voucher at all; it can stay off). You don't need to run ad-supported bundles, your own generated vouchers, or direct card sales alongside 1Voucher/OTT — a connected, verified gateway is itself a valid way for guests to connect, and a portal running only 1Voucher and/or OTT Voucher (everything else switched off) is fully supported.
External voucher bundles
Sits right next to Generate vouchers specifically so a portal running only 1Voucher/OTT (no card sales) has an obvious place to set pricing, without needing to know it's also called "Data plans" elsewhere. It's deliberately the exact same underlying bundle list as Data plans — add a bundle here and it also shows up there, and vice versa — since both panels are just two different ways a guest can pay for the identical bundle: by card, or from a redeemed voucher balance. Same fields, same per-bundle device limit, same optional promo abuse-protection, same optional per-router visibility restriction (see Data plans), same everything; only the surrounding copy differs.
On the captive portal, once a guest has a balance (redeemed just now, or already sitting there from before), "Use my balance instead" under the redeem box opens this same bundle list, cheapest first, scrolling internally if you've set up a long menu. Every bundle they can't currently afford is shown but disabled — never hidden — so a guest can always see full pricing even at R0 balance, useful for deciding whether it's worth topping up further before buying anything. Recharging without buying is completely normal and expected: the balance simply stays on their account, growing with every voucher they redeem (R2 now, R3 later becomes a real R5 balance), spendable whenever they choose — closing the modal without picking a bundle never loses anything.
Promo protection (stopping free-bundle abuse)
A bundle priced R0 is bait for abuse — a guest exhausts it, then either registers a new account on the same phone, or takes an already-used account and connects from a different phone, hoping the system treats it as someone new. Promo protection closes both: it checks the guest's device (a fingerprint unique to that phone or laptop) and their account (phone/email) together, not separately. Whichever signal has already claimed the bundle blocks the next attempt — switching only the account doesn't work, and switching only the device doesn't work either.
A bundle priced R0 gets this forced on automatically, with a strict "once ever" default, since a free bundle needs it the most. A paid bundle can turn it on too — useful for a steeply-discounted launch promo you still want rate-limited. Choose how often the same device or account can re-claim: once ever, hourly, daily, weekly, monthly, or yearly, plus an optional start and end date for a time-limited campaign. Configure it from the same form as the bundle itself, on either Data plans or External voucher bundles — they're the same underlying list, so the setting applies identically either way.
Guests don't find out the hard way — a guest who's already claimed a protected bundle sees it greyed out on the connect screen before they even tap it, not a failed attempt afterwards. Not unbeatable (a guest changing networks or devices entirely can still present as a fresh device fingerprint), but it closes the common "just sign up again" pattern without adding any friction for a genuine first-time guest.
Subscribers
A recurring account for your OWN regular customers — a fixed ISP-style line, not a one-off voucher or data plan. A subscriber logs in the same way any other recognized guest does (no separate password required), keeps the same account and the same optional static IP every time, and is billed automatically each cycle once a card is on file.
Subscription plans
The recurring packages subscribers choose from — e.g. "R150/month Unlimited". Set a name, price, and billing interval (weekly or monthly), plus a data allowance (a fixed MB bundle, or "Unlimited data") and optional download/upload caps that override your tenant-wide defaults for this plan specifically, the same relationship a data plan's own speed already has to the defaults in Bandwidth & speed caps.
Max concurrent devices works exactly like the same field on Data plans and Voucher presets: set it above 1 and "Allow adding extra devices" turns on automatically (it's server-derived, not something you set directly — the checkbox is shown disabled for that reason) so a second device can actually join the same subscription through the existing "Add a device" pairing-code flow instead of silently being refused despite the device count nominally allowing it.
Reserve a static IP for subscribers on this plan turns on the option to give every subscriber on this specific plan a fixed IP address on your network — see Static IP / reserved addressing below for what that actually does and which routers support it. Leave it off for a plan that's just "more data, same as any guest" with no networking difference.
The optional Fair usage override at the bottom of the form is the same mechanism as the platform-wide fair usage policy, scoped to just this plan — leave all three fields blank to inherit your tenant-wide FUP threshold/throttle exactly, or set your own numbers to give this plan a different rule (e.g. a cheap entry plan that throttles sooner than your flagship unlimited plan). It only ever takes effect while your tenant-wide FUP is switched on in the first place. Deactivate a plan (rather than delete it) to stop new subscribers signing up to it while leaving existing subscribers on it untouched; deleting is blocked outright while any subscriber is still assigned to it.
Subscriber accounts
Two ways a subscription actually starts. A guest can subscribe themselves from the captive portal's "Buy Internet Access" modal, grouped separately from one-off vouchers and data plans so it's obvious which button starts a recurring plan rather than a single purchase — this runs a real card checkout (see Recurring billing) and creates their subscriber record automatically the moment they pick a plan, tied to the identifier they're already logged in as.
The other way is from this dashboard, for a customer who paid you directly (cash, EFT, in person) rather than through the portal: search for them by phone, email, or name under "Subscribers" — this searches your real, already-recognized guest directory (the same one Guest activity and device management use), never lets you type in an arbitrary new phone/email — pick them from the results, choose a plan, and assign it. This deliberately does NOT create a fresh login with a password you invent: it attaches the subscription to the guest's real existing identity, so they're recognized automatically the next time they connect, exactly like any other returning guest. A cash-paid subscriber like this has no card on file and is never touched by the automatic billing sweep — you renew them yourself each cycle with the "Mark as paid" button, which extends their next billing date, reactivates them if they'd lapsed, and re-grants access on whatever device(s) of theirs are already on file.
The Subscribers table shows each subscriber's plan, status (trialing/active/past due/canceled/suspended), next billing date, and static IP if one's assigned. Search filters the same way as everywhere else in the dashboard. Removing a subscriber who's never actually been charged deletes them outright; one with real billing history can't be deleted (their charges are a financial audit trail) — set their status to Canceled instead, which stops future billing while keeping the record intact.
Static IP / reserved addressing (PPPoE-style)
The closest equivalent this platform has to a traditional ISP's PPPoE/static-IP account, built for someone who genuinely needs the same address every time — port forwarding, a security camera, a small office device that expects to be reached at a known address — rather than whatever the router's own DHCP happens to hand out that day. It's not a separate connection type: it's a static DHCP reservation layered onto an existing account, which is why it lives here instead of as a standalone feature.
Available in two places, deliberately not everywhere: on a subscriber (once their plan has "Reserve a static IP for subscribers on this plan" turned on), and on an internal account (no plan gate needed there — each internal account is already configured individually, so assigning one is the gate). SSO logins get this automatically as a result, since an SSO login already is a real internal account under the hood, not a separate record. It's scoped to these two specifically because both represent a persistent, ongoing device relationship — a resident, a member of staff, a paying subscriber who keeps coming back — rather than a one-off or short-lived grant. It deliberately does NOT extend to vouchers, external vouchers, data plans, surveys, or ads: those are bounded, often anonymous purchases or unlocks, and a permanent router-side IP reservation tied to one would just become orphaned configuration once that guest moves on. It also doesn't extend to roaming — a reservation only ever exists on one specific router's own local network, and roaming's entire point is a guest moving between different venues' different networks with no shared address space to reserve on.
From the subscriber or internal-account row, click "Assign IP", enter the IPv4 address to reserve, the device's MAC address, and which of your routers it connects through. Both the IP and MAC are strictly format-checked server-side before anything is sent to a router — an invalid value is rejected outright rather than forwarded. The reservation is pushed as a real DHCP static-lease command to the router itself (MikroTik and OpenWRT-family routers today), logged in the same router command audit trail Remote CLI uses, and applies the moment the router next checks in.
This reserves an address on YOUR local network only — it's a LAN-side DHCP reservation, not a public/routable IP or a real PPPoE tunnel, and doesn't require any change to how the device connects. If a subscriber's plan doesn't include static IP, or the router vendor isn't one of the two automated ones yet, assigning one is refused with a clear message rather than silently doing nothing.
Recurring billing, retries & cancellation
A card-based subscription runs on the SAME PayFast connection you've already verified for one-off data-plan checkouts (Payment gateways) — no separate setup. The first checkout both takes the initial payment and securely tokenizes the card for every later charge; the raw card number is never stored by this platform, only an encrypted token PayFast itself resolves. Every subsequent cycle (checked on the same 6-hourly sweep as your own platform subscription) charges that saved token automatically for the plan's price, extends the subscriber's next billing date, and sends them an SMS receipt with the amount and next billing date — the same receipt-SMS pattern used for cash renewals via "Mark as paid".
A failed charge doesn't cut anyone off immediately: the subscriber is marked past due, told by SMS that payment failed and that access pauses in 3 days if unresolved, and retried automatically every 6 hours. If it's still failing once that 3-day grace period passes, they're suspended — access is actually cut on the router, a final SMS explains why, and they stay suspended until you (or a successful retry) reactivates them. A subscriber can cancel their own renewal at any time from the "My Usage" panel on the captive portal ("Cancel subscription") — this only stops future billing; it never cuts off access already paid for, which keeps running exactly until the period they've already paid for ends, then quietly doesn't renew. Both the subscriber's own cancel action and every dashboard status change are logged the same way any other billing-affecting action on this platform is.
Security & abuse prevention
Subscriptions deliberately reuse every abuse-prevention mechanism already proven on vouchers and data plans, rather than a new, separately-tested set of rules. A guest starting or managing their own subscription is verified through the same session-ownership check every other self-service purchase on this platform uses (the same one guarding a data-plan checkout) — never a bare identifier typed into a request, so one guest can't view, cancel, or start a checkout against another guest's subscription by supplying their phone number or email. A dashboard-assigned (cash) subscriber is likewise always tied to a real, already-recognized guest found via search — never a freshly-invented login — closing off the fake-account risk that pattern used to carry.
On the payment side, the checkout webhook verifies PayFast's own cryptographic signature before trusting anything it's told, independently re-checks the amount actually paid against the plan's real price (a report of "payment complete" is never enough on its own — it has to be complete for the right amount), and is idempotent: replaying the same payment notification twice can never grant access or record a charge a second time. Starting a second checkout while one is still awaiting confirmation is blocked for 10 minutes to prevent an accidental double-charge from a guest who assumes a slow confirmation means it failed — with an explicit "try again now" option for a guest who genuinely canceled and wants a fresh attempt immediately, rather than making them wait out the full window.
Everything else that already protects paid/earned access applies here too, unchanged: the account's own fair usage policy (with this plan's own optional override), Fair Pause protection if a router goes offline mid-cycle, your tenant-wide device-bandwidth caps, and the concurrent-device limit enforced through the same "Add a device" pairing flow as every other multi-device plan. A subscriber's access window is capped strictly to their own next billing date server-side — it can never be extended by re-logging in or reconnecting, only by an actual successful charge (automatic or "Mark as paid").
Free access
Everything about letting specific people online without ads, a voucher, or a card — from your own instant login, to blanket free access for every guest, to named accounts you provision yourself. (The ad-watch route guests use most often is covered first below, even though it isn't strictly "free" for you — it's how the platform pays for itself without you charging guests directly.)
Ad-supported access (watch ads to unlock data)
The default way most guests get online: watch a set number of ads, earn a data bundle for a set number of hours, no card and no voucher needed. Out of the box every captive uses the same three tiers — 100MB for 5 ads (1 hour), 250MB for 10 ads (1.5 hours), 500MB for 15 ads (2 hours) — but you can replace them with your own from Free access → Ad revenue → Ad-unlock bundles in this dashboard: up to three tiers, each with its own data amount, number of ads required, and access duration. One tier is enough if you'd rather keep it simple; leaving all three untouched keeps the defaults live. A tenant that hasn't customized anything yet always shows the current defaults, never a blank or broken state. Whatever you set is enforced the same way on both routes a guest can earn a bundle through — watching the on-screen sequence on Home and the automatic top-up that fires as ad-watch progress comes in — so a guest gets the same bundle for the same number of ads no matter which one happened to trigger the grant. Guests always get full, uncapped speed while they're actively watching ads — including a guest who already has data and is watching more ads to top up — so ad playback never fights with whatever speed cap their current session has; see Bandwidth & speed caps for how that sits alongside the platform's other caps.
Ad pricing & minimum spend
What a business pays per ad view when they buy a campaign on your Marketing Page or through your Captive Dashboard. Five fixed ad formats exist platform-wide — Standard, Skip Disabled, Homepage Takeover, Aggressive, and Aggressive + Skip Disabled — each with its own built-in behavior (whether a guest can skip it, whether it gets extra rotation weight, and so on) that stays the same for everyone; what you control per captive is the price for each one, plus a minimum total campaign spend. Leave any price or the minimum spend blank and that captive simply uses the platform default until you set your own — nothing breaks and nothing charges the wrong amount in the meantime. Change a price from Free access → Ad revenue → Ad pricing and it updates everywhere a price is shown or charged for your captive specifically: the Marketing Page, the Captive Dashboard's campaign builder, and every revenue report — another captive's pricing is never affected, and a business can never pay less than what your dashboard actually has configured at the moment they buy, even if they tamper with the page in their browser. When building a campaign on the Captive Dashboard, an advertiser can also optionally restrict it to specific days of the week and/or an hour range (e.g. a lunch special that only shows 11:00–14:00 SAST) — the ad simply isn't shown outside that window, it doesn't pause the campaign or affect its budget/end date. Leaving every day checked and the hour fields blank (the default) runs it all the time, exactly like before this existed. If you run more than one router or location under this captive, a "Locations" picker on the same builder lets you restrict a campaign to specific ones instead of every router you own — a promo for one branch that shouldn't show at another, say. Leave every location checked (the default) to run everywhere, including any router you add later. The builder also has an optional "Frequency Cap" — off by default, meaning a guest can see a campaign as often as it's otherwise eligible to show. Turn it on and set a limit (e.g. 3 views per day, per week, or per month) and a guest who reaches it simply stops being offered that one campaign until the period resets; every other active campaign keeps showing to them as normal. Enabling it caps that campaign's own reach — a low cap can mean its budget/goal-views target takes longer to spend, or never fully spends — so it's best reserved for a genuine reason to avoid repeating the same guest too often (e.g. a one-time event promo), not turned on by default.
Brand takeover day — the same campaign builder has an option to make one campaign the ONLY ad shown, fleet-wide (or restricted to whichever Locations it also targets), for one full calendar day — a premium placement you price and invoice however you like, same as any other campaign. Check "Make this the ONLY ad guests see, for one full day" and pick a date; only one takeover can be booked per calendar day per captive, so a date that's already taken shows a warning as soon as you pick it. On its day, a takeover campaign still respects everything else that would normally keep an ad from showing that guest — age restrictions, Locations, budget/end date — it just wins over every OTHER active campaign that guest would otherwise have been eligible to see.
No payment gateway sits between you and the advertiser here — a campaign's spend (views delivered × your price, capped at its budget) is only ever tracked, on your My revenue tab and the Captive Dashboard's own reporting, so you always know exactly what to invoice or collect from that business. How you actually get paid — invoice, EFT, cash on your own terms — is entirely between you and the advertiser; ISN is never in that transaction and never takes a cut of it.
If ads are the only way guests get online at your captive (no vouchers, no data plans, no surveys) and a guest happens to hit the Frequency Cap on every single active campaign, "Connect" automatically falls back to showing them "My Usage" instead of leading to an empty ad player with nothing left to show — the same fallback a brand-new captive with no ads at all already gets. It switches back to "Connect" by itself the moment their cap period resets, or you upload a new campaign, or turn on another access mode — no page reload needed on the guest's end.
Survey-supported access (answer a survey to unlock data)
A third way for a guest to earn data alongside ads and vouchers: answer a short survey you (or a business at your venue, e.g. a mall tenant) curate, and unlock a data bundle — off by default, turned on from Surveys in this dashboard along with the rate you're paid per answer. On your Captive Dashboard's Surveys tab you write the questions (single-choice, multi-choice, star rating, yes/no, or free text), optionally assign a question to a specific business so only that business sees its own responses, set a Rand budget per question or pool a budget across several questions in a bundle, restrict a question to guests of a minimum/maximum age, and configure 1-3 unlock tiers guests choose from (e.g. "5 questions → 100MB, valid 24h"). A question only goes live once it passes automated AI review — see Survey safety & AI moderation below — and automatically stops showing once its budget is spent, with an email at 75% and 100% of budget so nobody is surprised by the cut-off. If a guest's age excludes some questions from a tier, they still get the full reward for answering whatever questions remain eligible for them, instead of being blocked from the tier entirely. Every response is anonymous — no guest identity is ever stored against an answer — and results (aggregate counts, or the full individual list) are visible to you and to the assigned business from their own dashboards, alongside what's been spent so far. Running more than one router or location? The same question builder has a "Locations" picker so a question can be restricted to specific routers instead of every one you own — left checked (the default) it runs at every location, same as before this existed.
Survey safety & AI moderation
Because this feature puts both a tenant and a guest in a position to write content another stranger will see, it's treated as a genuine security surface, not just a form. Every question is screened by an AI review step before it can go live, checking two separate things: whether the subject matter is actually age-restricted (alcohol, tobacco, gambling, weapons, drugs, sexual content, financial products, explosives) using real-world brand recognition rather than simple keyword matching, and whether the configured minimum age on that question is genuinely 18+ if it needs to be — a well-known alcohol brand with no age floor set is rejected even though the same question with an 18+ floor is approved. The review runs as a double-check (two independent passes must both agree before something is approved) and fails closed: if the AI service is unreachable or its answer can't be parsed, the question is rejected rather than silently allowed through. On the guest side, every free-text answer is length-capped and HTML-escaped everywhere it's ever displayed — to you, to the assigned business, and in exported reports — so a malicious answer can't inject a script or break a dashboard page. Guest responses are rate-limited, tied to a single-use "attempt" the server itself generates (so a guest can only ever submit answers to the exact questions it actually showed them, once), and anonymized by design: no name, phone number, email, or ID number is ever collected as part of a survey response.
Your own bypass (owner login)
The instant, no-voucher-no-ads access you get the moment you log in with your own dashboard credentials on your own captive portal. Choose unlimited data or a set MB cap, and a duration (2 hours, 24 hours, 2 months, 1 year, or never expires).
Open access for all guests
Extends that same instant access to every guest who logs in or registers — no voucher, no ad-watch, full internet the moment they arrive. A good fit for venues like student accommodations where you'd rather bill a flat rate than gate individual guests one at a time. Configure unlimited data or a cap, a duration, and how often the same physical device can claim a fresh free grant: once ever, daily, weekly, or monthly. "Once ever" is enforced by device fingerprint, not just the email or phone number someone signs up with — registering again on the same phone under a new identity doesn't get around it.
Internal accounts (named users)
Accounts you provision yourself for students, staff, or residents — a real, permanent alternative to a shared network password that inevitably leaks to outsiders. Each one bypasses ads and vouchers entirely, with its own data cap (or unlimited), its own duration (a rolling preset, or an exact custom expiry date), and its own device limit so one login can't quietly become the whole building's free WiFi. Duration presets match the owner bypass above: 2 hours, 24 hours, 2 months, 1 year, or never expires; "exact date & time" pins it to a real calendar deadline instead (e.g. a lease end date) — once that date passes, the account is permanently and automatically shut out, no manual cleanup needed. Its own download/upload speed cap (Mbps) is optional too — leave at 0 to just inherit the tenant-wide default described under Bandwidth & speed caps.
A device only counts against the device limit while it's actually still connected, not for the rest of whatever duration the account was granted — a 5-minute visit under a 24-hour grant doesn't lock that slot for the remaining 23-plus hours. A device is freed automatically after roughly 10 minutes with no sign of it: neither the captive portal itself nor, where your router reports connected devices, the router's own hardware-level confirmation. A device that's still genuinely online keeps its slot the whole time it's connected, whether or not it ever revisits the captive page again — closing the browser tab doesn't cost it its spot.
Unit / room / ward tagging — an optional free-text label on each internal account (e.g. "Ward 4A", "Room 212"), for a hospital, student residence, or other multi-unit site that wants to scope usage to a physical unit without running a separate router per room. Purely a label you set yourself when adding or editing an account — there's no automatic physical-location detection here, "room 4A2" only means whatever you type. Filter the account list by unit from the field above the table to see everyone in one unit at a glance.
Fair usage override (optional) — each account can optionally set its own throttle threshold and speed, overriding your tenant-wide fair usage policy just for that account's own direct logins (leave blank to use the tenant default). Distinct from a voucher this account issues to a visitor, which is covered by the older, separate monthly resident-voucher fair usage policy instead.
Static IP (optional) — click "Assign IP" on any internal account to give its device a fixed, always-the-same LAN address instead of whatever DHCP hands out — useful for a security camera, POS terminal, or office device tied to that account. No separate setting to turn on first; see Static IP / reserved addressing for exactly how it works and its limits.
Single Sign-On (SSO)
A second, zero-maintenance way to run internal accounts: instead of you adding each student or staff member by hand, a guest signs in with the login they already have at your institution — Google Workspace, Microsoft/Entra ID, Okta, or any other OIDC or SAML identity provider — and their account is created automatically the moment they first sign in. Nobody's password is ever stored on this platform for an SSO-provisioned account; every sign-in is verified live against your own identity provider, so revoking someone's access at the source (e.g. offboarding a staff member in your own IT system) locks them out here too, automatically, with nothing for you to remember to do on this end.
Setting up: turn it on under Free access → Single Sign-On, choose OIDC or SAML, and enter your identity provider's own details — Client ID/Secret for OIDC, or your IdP's metadata for SAML. Your own Redirect URI (OIDC) or ACS URL and SP metadata (SAML) are shown right there to paste into your identity provider's console, generated for your own domain automatically. An optional email-domain allowlist restricts sign-in to addresses on your own domain(s) — leave it blank to accept any account your identity provider itself authenticates.
Auto-provisioning defaults: the same fields you'd set by hand on a regular internal account — data cap or unlimited, duration, device limit, speed caps, and an optional fair usage threshold/speed (blank falls back to your tenant-wide default) — just applied automatically to every account SSO creates for you, so first-time sign-ins never land with the wrong access level. Change the defaults any time; they only affect accounts provisioned from then on, not ones already created — an already-provisioned account keeps whatever it was given at creation until you edit that specific account afterward, the same as any manually-added one. Duration works the same way here too: a rolling preset (2 hours through never expires), or "exact date & time" to pin every account SSO provisions to one fixed cutoff instead — useful for a semester or term that should end the same day for everyone, regardless of when each person actually first signed in. If that fixed date passes and nobody's updated it since, new sign-ins fall back to the preset duration rather than provisioning an account that's already expired the moment it's created.
Works alongside Roaming Partners too — see that section below for how an SSO-provisioned guest roams at a partner captive without ever typing a password there.
Roaming Partners
Lets a guest with an internal account at a PARTNER institution log in at YOUR captive using their own home credentials — the same idea as mobile carrier roaming or eduroam. A visiting guest types theirusername@theirschool.ac.za instead of just their username; the @realm tells your captive which partner institution to check the password against. A bare username with no @ never triggers this at all — it only ever checks your own accounts, exactly as before, so a raw student number stays exactly as safe as it already was.
Setting up: first set your own realm under Roaming Partners in your dashboard — a short domain-style name (e.g. yourschool.ac.za) unique to you on this platform; you can't connect to anyone or be connected to until it's set. To connect with a partner, generate a one-time connection code and share it with them yourself (email, phone — this platform never shows you a directory of other tenants to search or contact). They paste your code into their own dashboard; you'll then see a request waiting for your accept before anything goes live. Redeeming a code alone is never enough on its own — the institution that generated it must explicitly accept too, so neither side is ever pulled into sharing guest data with a partner they didn't actually agree to.
Roaming with an SSO account: a visiting guest whose home institution uses Single Sign-On instead of passwords is redirected through their own home institution's sign-in page automatically — never a password prompt, and never your partner's login screen out of context. They authenticate exactly the way they would at home; your captive only ever receives proof they're a valid, currently-active account there, never their identity provider's tokens or session. If either institution's partnership is paused, or the visitor's device is already at your outsider device-limit below, they're declined right on your own login screen — never redirected somewhere first that might suggest they have a chance of getting through.
Outsider access rules: one set of rules per tenant, applied the same way to a visitor from any of your partners (not configurable per individual partnership) — unlimited data, or a cap in MB that resets daily, weekly, or monthly, plus a max concurrent visiting devices limit and its own speed caps. This is completely separate from your own students' account settings, and from your partner's — a visitor is always governed by whichever institution's network they're actually standing on. The same freshness rule described under Internal accounts applies to this device limit too — a visitor only occupies a slot while actually connected, not for their entire grant.
Pausing without disconnecting: either side of an active partnership can pause incoming roaming at any time, without deleting the connection itself — resuming later needs no fresh code exchange. Your partner can always see your current status (and you theirs) on the Roaming Partners page, never silently.
Reporting: two views, both on the same page — who's visiting YOUR network from a partner (grouped by which institution, with session counts and data used), and where YOUR OWN accounts have been seen roaming at a partner (the mirror view). Both are aggregate/session-level only; connecting with a partner never hands either side a bulk list of the other's account identities.
Fair usage override (optional) — visiting roaming guests are covered by your tenant-wide fair usage policy automatically, same as any other guest at your venue. Optionally set a separate threshold/speed just for roaming visitors right here alongside your other outsider access rules (data cap, device limit, speed caps) — ONE consistent rule applied to every partner you host, not configurable per individual partnership, matching the "one set of outsider rules per tenant" convention above.
Cross-venue campaigns
A national brand (e.g. a bank) sponsoring free data across several venues at once — entirely between you and them. ISN never brokers the deal, never sees the terms, and never touches the money; this is a direct, tenant-to-tenant arrangement, the same way Roaming Partners is.
Building your network: generate a one-time connection code and share it with a venue yourself (email, phone — this platform never shows you a directory of other tenants). Each code works once; generate a new one per venue. Redeeming a code joins that network immediately, no separate approval step — the real consent gate is per campaign, not membership itself. A venue can belong to several different networks at once. By default, venues in your network can't see who else is in it; turn on "let venues see each other" in Cross-venue campaigns to share names only — never prices or budgets — with everyone in the network.
Adding the sponsor: add them like any other business, via "Add Business" on your captive's own dashboard — just set account type to "Sponsor/Bank." They get a normal emailed invite to set their own password. A Sponsor/Bank business isn't locked into cross-venue only — the same business can also be attached to an ordinary, single-venue campaign directly, exactly like any other advertiser. When they log in, they see a read-only report of everything sponsored with you — cross-venue campaigns and any direct campaign, listed separately, each venue's numbers kept apart and never mixed together.
Posting a campaign: from Add Ad Campaign on your captive's own dashboard — attach it to a Sponsor/Bank business and a "Post as cross-venue campaign" toggle appears. Turn it on and it's posted (with a suggested starting price) to every venue currently in your network instead of going live at just yours. Each venue reviews it and either proposes their own price per view, or declines with a reason (emailed to you and the sponsor).
Budget modes — choose when posting: Individual (default) — you approve each venue's proposal separately, setting that specific venue's own budget cap; it stops on its own once that venue's cap is reached, completely independent of every other venue. Pooled — one shared budget for the whole campaign instead; every approved venue draws from the SAME pool as views come in (checked roughly once a minute), and the moment the pool runs out, every venue's ad pauses together, all at once — the right choice when a sponsor wants to split one fixed amount of money across several venues rather than fund each one separately.
Managing an ongoing relationship: under "Venues in my network," Manage opens everything one specific venue has pending across every campaign with you, so you don't have to hunt through each campaign separately — the same table also shows each venue's default price at a glance. Under "Networks I've joined," Manage lets you set a default price per view for that network — it pre-fills (never auto-submits) the price field the next time that network posts you a campaign, and IS visible to the network owner as your general rate (not binding — you can still propose a different price on any specific campaign). It also shows the other venues in the network if the owner has chosen to make that visible.
Visibility: you (the network owner) see full detail across every venue — prices, budgets, statuses. Each venue only ever sees its own numbers, never another venue's. Either side can withdraw an already-running campaign at any time, stopping it immediately, the same way turning off any of your own ads does.
Guest vouchers from residents
The answer to "my tenant's friend needs internet for the afternoon" without reopening the whole network to strangers. When switched on, any internal account can generate a voucher from their own My Usage panel and hand it to a real visitor — a random signup with no connection to a resident gets nothing at all. Configure the data cap per voucher (or unlimited), how many of the visitor's own devices can share one voucher (their phone and laptop, not a stack of unrelated guests), how many vouchers one resident can create per day, a download/upload speed cap for visitors specifically (separate from the general guest default), and curfew hours. Set both a start and end time and the voucher only works inside that window — outside it, residents can't create new ones, visitors can't redeem existing ones, and anyone already connected through one is disconnected the instant curfew starts. The same code can't be reused once curfew reopens the next day; a fresh one has to be issued.
Fair usage policy — resident guest vouchers (monthly, soft/hard)
This is a narrower, older policy scoped specifically to guest vouchers from residents — for a fair-use policy covering everything guests can buy or earn on your captive portal generally (data plans, your own vouchers, ad-supported and survey-supported access), see Fair usage policy — all paid & earned access below instead; the two run independently and you can use either, both, or neither.
Stops resident-issued guest vouchers from quietly turning into unlimited free WiFi for a rotating cast of visitors — on by default. Once a resident's guest vouchers move more than your monthly limit (in GB) of data combined, or one visiting device moves that much data across any resident's vouchers, your chosen policy kicks in. Soft mode throttles the resident's vouchers, and any visitor already connected through one, down to a speed you set — live, immediately, without waiting for anyone to reconnect. Hard mode stops that resident issuing any new vouchers, and blocks that specific visiting device from redeeming any resident's voucher at all, until the policy resets on the 1st of the next calendar month. The device-level check exists specifically because the account-level one alone would be trivial to dodge: FUP is tied to the visitor's physical device, not the identity they signed up with, so logging out and registering again doesn't reset anything, and trying a different, not-yet-limited resident's voucher just gets caught by the same device check on that voucher too. Every guest visiting an already-limited resident is affected the same way, not just the one who tripped the limit, until the next month begins.
Fair usage policy — all paid & earned access
The broad, tenant-wide version — off by default, turned on from Free access → Owner & guest access → Fair usage policy — that catches "unlimited" or generously-sized access being quietly used for hundreds of gigabytes, no matter how a guest got online: a data plan or external voucher bundle bought by card or balance, a code from Generate vouchers or a voucher preset, an ad-watch bundle, or a survey-unlock bundle. Distinct from the narrower resident-guest-voucher fair usage policy above (monthly reset, soft/hard mode, residents-only) — this one resets on a genuine rolling 24-hour window and only ever throttles, it never blocks. Set a threshold in GB and a throttled download/upload speed (Mbps, set independently — a plan can throttle to a slower download than upload, or vice versa); once a guest's currently-relevant usage crosses that threshold, their speed drops to the throttle speed immediately, live, without needing to reconnect. Turning the tenant-wide toggle off turns the whole policy off everywhere at once, including every override below.
What counts, and for how long. A bundle counts toward usage if it's still active right now (covering it for its FULL life — a 30-day or even year-long plan stays monitored the entire time, not just its first day), or if it was granted within the last rolling 24 hours even if it has already expired (so a short voucher that already ran out still counts for the rest of that day). This closes two real loopholes an admin flagged while this was being built: letting an over-threshold bundle expire and buying a fresh one does not reset anything — the old bundle's usage still counts against the window it's still inside, so if it was already over its own threshold, a newly-bought bundle right after it stays throttled too, only genuinely resetting once that old usage ages fully out of the 24-hour window. Chaining several small vouchers to individually stay under a single threshold doesn't work either, for the same reason: everything granted in the last 24 hours adds up together.
Each bundle (or pooled group) is judged against its own rule. If a guest holds several bundles at once with different overrides (see below) — say a 30-day/100GB plan and a top-up voucher bought on top of it — each is checked against its own threshold, and if more than one is over at the same time, the strictest download speed and the strictest upload speed each apply independently (never averaged), since the router can only enforce one download/upload pair per device. Buying a plan with "add extra devices" turned on (either a shared-balance voucher, or a data plan with its device limit raised above 1) pools every device sharing that one purchase into ONE combined threshold — two devices using 60GB and 40GB on the same 100GB-threshold plan trip the throttle together at 100GB combined, not 100GB each. A related loophole is closed the same way: a throttled guest logging out and registering again under a different phone/email number on the same physical device is still caught, since usage is pooled across every identifier that has shared that device — not just the identity that happened to trip the limit.
Per-item overrides. Every sellable/earnable item can optionally set its own threshold and throttle speed, overriding the tenant-wide default just for that item, while the tenant-wide toggle stays the master switch (an override does nothing while the policy itself is off): data plans and external voucher bundles (the same underlying bundle, so one setting covers both), voucher presets, a Generate vouchers batch, each ad-unlock tier, each survey reward tier, and each internal account's own direct logins. Leave a field blank on any of them to fall back to the tenant-wide number instead — useful for a cheap 24-hour top-up that should throttle much sooner than a full 30-day plan.
Covers every way a guest gets online, not just the obvious ones. Internal accounts logging in directly are covered automatically (with their own optional per-account override, set right on that account), separately from the older monthly policy that covers vouchers an account holder issues to someone else. Roaming-partner guests visiting from another tenant's realm are covered automatically too, at the VISITED tenant's own settings — with an optional roaming-specific override sitting alongside that feature's other outsider access rules (one consistent rule for every partner you host). Single Sign-On has its own fair-usage default too, on the SSO settings page — baked onto every account SSO auto-provisions from then on, the same way its other auto-provisioning defaults (data cap, duration, speed caps) already work; leave it blank and a newly-provisioned account just inherits the tenant-wide default like everything else. Whichever setting applied at the moment an account was created stays that account's own override afterward — editable per-account any time from the internal accounts list, exactly like a manually-added one.
Resetting the throttle for internal & SSO accounts. An internal account is usually added for months or years and reuses the same data allowance for its whole validity window instead of getting a fresh bundle the way a voucher or data plan does — so without a reset, once one crosses the threshold above it stays throttled at the reduced speed for the rest of its lifetime, even the month after the heavy usage happened. Turn on a reset from Free access → Owner & guest access (the same control also appears on the SSO Settings page and on the internal-accounts "Add an account" form, all three writing to this one tenant-wide setting): Never keeps today's behavior (a lifetime allowance, lifetime throttle once crossed); Rolling restores normal speed once a set number of days has passed since the account was last over threshold — good for "30GB a month, but the month starts whenever their usage actually began," e.g. a mid-month sign-up; Calendar month restores it on the 1st, matching a fixed billing cycle instead. Only the fair-usage throttle window resets — the account's own real data usage total and its expiry date are completely untouched, so this never hands out extra data or extends anyone's account.
Switching to a different account on the same device doesn't reset it either. A common real-world dodge in shared housing (a hostel, a boarding house, a student residence): a resident whose own internal/SSO login is throttled logs out and signs back in using a housemate's DIFFERENT, still-healthy credentials on the SAME device, hoping to inherit that account's full speed instead. This is caught the same way as the plain "log out and register again" dodge above — usage is pooled across every identifier that has shared this device — checked at the moment ANY internal/SSO/roaming login lands on it, so the housemate's account gets the throttle immediately on that first login too, not just after it separately crosses its own threshold.
How fast it reacts. Enforcement runs two ways together: the moment a connected guest's own usage report crosses their threshold (effectively real-time, the same reporting cadence live usage figures already use elsewhere on this dashboard), and a background safety-net check every 5 minutes that also catches anyone the first path missed — a guest who was offline when they crossed it, say. This means it holds up just as well on a short 30-minute or 1-hour voucher as it does on a multi-day plan, not just on long sessions where a small delay barely matters.
Survives a restart, either side. All the numbers this policy depends on live in your account's database, never only in a router's or server's temporary memory — a router reboot or a brief server restart doesn't reset anyone's usage count or quietly "forget" someone was throttled. The safety-net check above runs again the moment things come back online (not just on its usual 5-minute clock), so enforcement catches back up within moments either way.
SMS alerts, on by default (turn off from the same settings panel), text a guest's phone twice: once at 80% of their threshold as a heads-up, and again the moment they're actually throttled — each guest is only messaged once per condition per 24 hours, so hovering right at the edge doesn't spam them repeatedly. Skipped automatically for a guest who only ever gave an email address.
Shared & multi-tenant properties (landlord/ISP WiFi)
A recurring problem for accommodation blocks, boarding houses, and any property with one WiFi line serving many separate tenants: the network feels slow even though the line itself is fine, because far more devices are on it than there are paying tenants — the one shared password inevitably gets handed to outsiders, and rotating it just starts the leak over again. Four features on this platform, used together, close that loop instead of fighting it manually.
Stop issuing one password at all. Give every tenant their own internal account instead — its own login, its own data cap or unlimited allowance, its own device limit, and its own duration (a lease-end date works well here). There's no single "main" credential left to leak in the first place, and a device limit per account means one tenant's account can't quietly become the whole building's free WiFi even if they do share their own login.
Let real guests connect without reopening the network. Guest vouchers from residents, switched on by you, lets any tenant generate a voucher from their own My Usage panel and hand it to an actual visitor — a random signup with no connection to a resident gets nothing at all. Each voucher carries its own data cap, a device limit (a visitor's phone and laptop, not a stack of strangers), a daily limit on how many a resident can issue, its own visitor speed cap kept separate from the resident's own line, and optional curfew hours — set a start and end time and the voucher stops working outside that window, with anyone already connected through it disconnected the instant curfew begins; the same code isn't reusable once curfew lifts the next day.
Catch the loophole a resident-level check alone would miss. The fair usage policy, on by default, tracks usage by the visiting device, not the identity it signed up with — so a visitor who's used up one resident's fair share can't just log out, sign up again, or borrow a different resident's voucher to keep going; the same device check catches them on that voucher too. Soft mode throttles the affected resident's vouchers live; hard mode blocks that resident issuing new ones and blocks that specific visiting device from redeeming anyone's voucher, until the policy resets on the 1st of the next month.
Shrink the signal, not just the guest list. WiFi signal / coverage control attacks the same problem from the radio layer instead of the login screen: lower a router's broadcast power on 2.4GHz and/or 5GHz (independently) so it barely reaches past your own property line — the neighbouring unit, the shop next door, or someone parked on the street stops seeing a usable signal to begin with, rather than seeing one and being turned away at login. It's reduce-only and hard-capped at South Africa's ICASA license-exempt ceilings (see WiFi signal / coverage control for the exact limits), so you're narrowing reach, never boosting past what's legally exempt. Used alongside the three features above, it cuts down how many outsiders ever reach your login screen at all, while internal accounts, guest vouchers, and FUP handle whoever still does.
Repeat-guest rewards
Automatically grants a bonus data bundle to a guest every time they hit a visit milestone — off by default. A "visit" counts once per calendar day, using the same device-recognition the platform already relies on elsewhere, so watching several rounds of ads in one afternoon is still one visit. Set how often to reward (e.g. every 5th visit), and the bonus bundle's size and duration; the reward lands automatically, with nothing for the guest or you to do. Only counts real guest activity — an owner or team member accessing their own network via owner bypass never counts toward it.
Guest satisfaction (NPS)
A free, one-tap "how was your visit?" prompt — off by default, turned on from Free access → Guest satisfaction (NPS). When it's on, tapping "Log out" on the captive Home screen opens a small prompt with three faces (🙁 😐 🙂) and an optional one-line comment, right before the guest is actually logged out; tapping a face, or "Skip," both complete the exact same real logout either way — a guest is never blocked from disconnecting by this. Nothing is bought or sold and no reward is offered or expected, unlike Survey-supported access, which pays a guest in data for answering; this is purely feedback for you, and every response is anonymous, with no guest identity ever stored against it.
Results live on the same settings panel: an average score out of 3, total responses over the last 30 days, the % who tapped happy versus not-great, and the most recent written comments, newest first. There's no obligation to act on any single comment — it's a lightweight pulse-check, not a formal review queue.
Google review bonus
A different kind of reward — off by default, turned on from Free access → Google review bonus — offering bonus data for leaving a Google review, distinct from the private feedback above. Paste your Google review link (from your Business Profile's "Ask for reviews" tool, or your Maps listing's own share link) and set the bonus (data amount and duration). A guest sees an option to leave a review and earn the bonus; tapping it opens your review link in a new tab and reveals a "claim my bonus" button.
Two things worth understanding plainly. First, the reward is for leaving a review, never for a positive one — Google's own policies prohibit incentivizing reviews conditioned on sentiment, so nothing here asks for or checks a star rating. Second, this runs on trust: there's no realistic way for a platform serving many separate tenants to confirm a specific anonymous Google review actually came from a specific guest (Google doesn't expose that kind of lookup), so a guest who taps "claim my bonus" is simply trusted to have followed through — the same honor-system approach most guest-WiFi review tools use. The bonus is granted once per guest, ever, per captive.
Marketing
Tools for putting your WiFi in front of guests and bringing past ones back — no separate marketing platform needed.
QR flyer
A printable "Scan to connect" flyer generated right in your browser — nothing uploaded anywhere. Set your own heading, click Generate, and the QR code points straight at your captive portal's real URL, so scanning it drops a guest directly onto your Captive Login. "Print / save as PDF" opens it in a clean print layout for your front desk, tables, or rooms. Needs your portal to be published first — see Dashboard home.
Re-engage guests
A one-off SMS campaign to guests who connected recently, spending your own SMS credits (see Buy credits). Choose a recency window (7/14/30/90 days) to see how many guests are eligible, write your message ({{BRAND}} becomes your own brand name automatically, same as every other SMS this platform sends), and re-enter your password to send — the same password check used for Remote CLI, since this both spends credits and reaches real people in bulk. Capped at 300 recipients per send, and any guest already sent a campaign message in the last 7 days — from this campaign or an earlier one — is automatically skipped, so nobody gets re-blasted back to back.
Automated win-back
The scheduled version of Re-engage guests above — off by default, since once enabled it spends SMS credits on its own with nobody clicking send. Turn it on and set three things: how many days of inactivity counts as "gone quiet" (default 14), how many times a guest must have bought a voucher or data plan before to count as a real past customer (default 2), and how long to wait before messaging the same guest again (default 30 days). A daily check texts every guest who matches all three, using your own message ({{BRAND}} works the same way here too). Because it runs unattended, a single run is capped at 50 sends per check regardless of how many guests match, and it stops for the day the moment your SMS credits run out rather than failing loudly.
Network
Your actual hardware — adding it, controlling it remotely, and filtering what it can reach — all from the dashboard, with no vendor RMS portal or SSH session required for everyday changes.
Routers
Add a router with a name, a location, and an optional router ID (auto-generated if you leave it blank). You'll get a one-time SSH command to run on the physical device — it needs to be OpenWRT-based (Teltonika RutOS, GL.iNet, or similar) — plus the External Login URL to set in that router's own Hotspot settings so it knows where to send guests, pointed straight at your Captive Login. From there, every router in your fleet shows online/offline status, connected device count, and last-seen time, and an "Auto-config" wizard walks through vendor-specific setup. Fully automated (a one-time script does the work): Teltonika, GL.iNet, generic OpenWRT (also the right pick if you've flashed OpenWrt onto a supported Cudy model — Cudy's own stock firmware isn't OpenWRT-compatible), and MikroTik (access control, content filtering, and RADIUS if you've turned it on; WiFi/bandwidth settings still need configuring on the router itself). Automated via cloud API instead of a script: Cisco Meraki (paste a Dashboard API key plus your network and SSID number, and it points that SSID's splash page straight at your Captive Login — content filtering and RADIUS aren't covered for Meraki yet, since Meraki's own settings for those work differently from every other router here) and TP-Link Omada (paste your Controller URL and a hotspot-operator account, and ISN tells the Controller a guest is authorized the moment they're granted access on our side — the one thing you still set by hand in Omada's own UI is the SSID's Portal Type and External Portal URL, shown to you once your credentials verify successfully; content filtering and RADIUS aren't covered here either). Everything marked "beta" above hasn't been verified against real hardware yet. Guided manual instructions only (no automation): Cisco WLC/ISE, Cisco small-business (RV/WAP), stock Cudy firmware, Cambium (cnPilot/cnMaestro), Ruckus, and "Other" — each gets guidance actually specific to that hardware (an ISE RADIUS server, for instance, is exactly what the RADIUS authentication panel below is for) rather than one generic snippet. Click into any router to set its WiFi name/password (or run it as an open network), speed caps (see Bandwidth & speed caps next), restart it remotely, or deactivate it without losing its history. Each router in the list shows its own live Download/Upload Mbps and device count — not a combined total across your fleet — since a busy or struggling router is often just one of several, and you need to tell which one from the list itself. Once an hour, each router also runs a small, bounded (2MB) speedtest against its own ISP line — shown separately as "ISP line speedtest" with latency, download, and upload — so you can tell "my internet line itself is slow" apart from "my own caps/guest sharing is the bottleneck." Deliberately small and infrequent so it never meaningfully eats into a metered data line or competes with real guest traffic.
Rotating WiFi passwords at scale. "Rotate WiFi password for all routers," above your router list, applies one new name/password to every OpenWRT-family router (Teltonika, GL.iNet, generic OpenWRT) in one password-confirmed action — no need to log into each router individually, and no risk of guests bouncing between APs with mismatched credentials mid-venue. A MikroTik or other-vendor router isn't covered by this push and needs its own Hotspot WiFi settings changed directly. Separately, most routers already self-update their own agent automatically the moment a new capability ships — a banner only appears above your router list when one genuinely predates that mechanism and needs a single manual reinstall to catch up; after that, it stays current with zero further action from you.
Standing in for a broken-down bus. A journey preset that's router-restricted for fare-enforcement can't normally tell a genuine relief-bus transfer apart from someone fare-dodging onto a different bus — both look identical from the router's side. If a bus breaks down and passengers move to a different vehicle, open the replacement router's own Manage panel and set it as "temporarily standing in for" the broken-down one, so already-paid passengers moved onto it keep working instead of getting wrongly cut off. Clears itself automatically 24 hours after it's set — nothing to remember to undo, and it can never quietly turn into a permanent way around that route's fare restriction.
Zero-touch enrollment (QR codes)
Pre-generate setup codes for routers you don't have in hand yet — useful when you're rolling out several at once. Under Your routers → Zero-touch enrollment, pick MikroTik or OpenWRT-family, choose how many, and generate — each one becomes a QR code and a short link, shown together in a printable sheet ("Print QR sheet"). Give one to whoever's actually installing that router (a driver, an on-site installer, a courier) — they open it, no ISN login needed, optionally name the router and its location, and get that vendor's exact install command with step-by-step instructions and a copy button. Submitting the form creates the router in your dashboard immediately, the same way adding one yourself does.
This isn't fully hands-free — someone still has to paste the command into the router's own terminal. A browser genuinely can't reach a router's local admin page directly from an HTTPS site (a real browser security limit, not something this platform can route around), so a phone scanning a QR code can't configure a router purely on its own. What this removes is you being the one who has to be there, or generate/walk through the install command live, for every single unit.
Each code is single-use and shows the install command exactly once, right after it's claimed — if whoever's setting it up navigates away before copying it, you can get it again from that router's own Manage page instead of reusing the code. A code can be revoked any time before it's used; a used or revoked code can't be claimed again. Codes never expire on their own, so you can generate and print a batch well ahead of when you'll actually need them.
Router groups
Tag routers into named groups (e.g. "Ground floor", "Branch A") so a bulk change reaches just that group instead of one router at a time or your entire fleet — worth setting up once you're running more than a handful. Create a group, assign routers to it from the dropdown, then apply a speed cap to the whole group in one action, or scope "Rotate WiFi password for all routers" above to a single group instead of every router. Purely an organizational label: a router not in any group behaves exactly as it always has, and deleting a group only ungroups its routers — it never touches the routers themselves. Group names also drive the "Revenue by department" table in My revenue — rename or regroup here and that report reflects it immediately.
Firmware version tracking
Each router's real firmware/OS version now shows on its own card in your router list — OpenWRT-family routers (Teltonika, GL.iNet, generic OpenWRT) report it automatically on their regular check-in; MikroTik routers don't have a continuous telemetry loop yet, so theirs is checked once a day via the same read-only command channel already used for other automated MikroTik checks.
How "outdated" is decided — deliberately not a maintained vulnerability list. We don't try to keep a live database of which specific firmware versions have which CVEs — that kind of list goes stale fast, and a wrong or outdated entry would be actively misleading for a real patching decision. Instead, a router is flagged only when it's running an older version than another router of the same vendor already elsewhere in your own fleet — if 4 of your 5 MikroTik routers are on 7.15 and one is still on 7.9, that one gets flagged; a single router, or a version nobody else in your fleet has beaten yet, is never flagged since there's nothing real to compare it against. A banner above your router list summarizes every outdated one, grouped by vendor, with a direct link to that vendor's own official release notes/security advisory page so you're reading the source, not a copy of it.
This tells you when a router has fallen behind the rest of your own fleet — it is not a vulnerability scanner and doesn't claim to know about any specific CVE. For actual security advisories, check the vendor's own page linked in the banner (MikroTik's changelog, OpenWRT's own advisory list, or your router vendor's support site).
Multi-WAN failover
Automatically switches a router's guest traffic to a backup internet connection if the primary one goes down, and switches back once it recovers — the same idea as a business having a fibre line with an LTE line as backup. This is entirely config we push to a connection you've already physically wired up; we can't create the second connection itself, only make the router use it correctly once it exists. Found on each router's own Manage view (only shown for supported vendors).
MikroTik uses RouterOS's own native distance-based routing: two default routes are configured, the primary at a lower distance (tried first) and the backup at a higher one, both with check-gateway=ping so RouterOS actually notices when the upstream ISP stops responding — not just when the physical cable is unplugged, which is the far more common real outage. You'll need to enter both gateway IPs (found under IP → Routes in Winbox/WebFig). OpenWRT-family routers (Teltonika, GL.iNet, generic OpenWRT) use mwan3, a standard, widely-used OpenWRT package — installed automatically the first time you turn this on for a router, never touched otherwise. You'll need the exact interface names for both connections, already configured under Network → Interfaces on the router itself.
Once enabled, which WAN is currently active is checked every 5 minutes and shown right on the router's Manage view, with a running history of every switch below it. A switch to backup sends you an alert the same way a router-offline alert does (toggle it separately under Notifications) — worth treating as "your primary line needs attention," since guests should stay online through the switch itself, that's the point.
Turning this off is bookkeeping only — we deliberately never auto-remove the routes/config already pushed to the router, since doing that automatically risks dropping a guest's connection mid-failover, and there's no reliable way to tell our own pushed config apart from something you've since changed by hand. If you want it fully removed, do that directly on the router. Not yet verified against real hardware.
Smart Queue Management (call quality)
Keeps video calls and voice calls smooth even while someone else on the same router is downloading something large — the technical term for the problem this solves is bufferbloat (a connection that's technically "up" but so backed up with queued traffic that everything feels laggy). Found on each router's own Manage view, right below Multi-WAN failover.
Deliberately not "detect this is a video call and prioritize it." Modern call and video apps (WhatsApp, Zoom, Teams and similar) mostly use unpredictable, constantly-changing ports specifically to avoid that kind of filtering, so building rules around specific ports or apps would be unreliable — and we'd rather not claim a precision we can't actually deliver. Instead this uses CAKE, a real, widely-deployed fair-queuing algorithm (it's the OpenWRT project's own recommended fix for bufferbloat) that achieves the same practical outcome a different way: it shares the connection fairly based on how much bandwidth each individual connection is actually using, moment to moment. A voice call naturally uses very little bandwidth compared to a bulk download, so under CAKE it naturally keeps flowing with low delay — no need to know or guess what app it belongs to.
Enter the WAN interface name (same field as Multi-WAN's own interface names) and your download/upload speed in Mbps — set these to roughly 90-95% of the router's real measured line speed (see its ISP line speedtest under Routers), not the full advertised speed. This matters: bufferbloat happens in equipment upstream of your router that this feature can't control, and giving SQM a slightly-lower ceiling to manage is what lets it actually stay ahead of that congestion instead of just adding another queue behind it.
OpenWRT-family routers use sqm-scripts, a standard OpenWRT package (installed automatically the first time you turn this on, same as mwan3 above). MikroTik uses RouterOS 7's native CAKE support — this needs RouterOS 7 or later, and is genuinely the least-tested piece of everything built in this session; if you're able to, try it on a spare or low-priority router before relying on it somewhere that matters. Same as Multi-WAN, turning this off is bookkeeping only and doesn't remove the queue config already pushed to the router.
Config backups
A safety net for every config push this platform makes to a router: firewall hardening, content filtering, Smart Queue Management, and Multi-WAN failover. Found on each router's own Manage view. A backup is taken automatically right before any of those four changes is pushed — you don't have to remember to do it — and a "Back up now" button is there for taking one any other time, e.g. before you experiment with settings yourself directly on the router.
A backup is the router's own real export format, not a bespoke format only this platform understands — MikroTik's own /export command, and the equivalent for OpenWRT's UCI config system. Restoring one replays it back, which is the standard, documented way both platforms expect a config to be restored, rather than this platform inventing its own undo mechanism per feature.
WiFi password and RADIUS shared secret are deliberately never included in a backup, on either vendor — MikroTik's plain export already leaves secret values out by RouterOS's own default behavior, and the OpenWRT backup is deliberately scoped to only the config sections this platform manages (firewall, SQM, Multi-WAN, network, DHCP) rather than a full device export, skipping the sections that hold WiFi and RADIUS secrets. This also means restoring a backup can never blank out a working WiFi password.
Restoring is a real, destructive action — it replaces the router's current config in those sections with whatever was saved — so it asks you to re-enter your dashboard password first, the same step-up check as firewall hardening and Remote CLI. Only the 20 most recent backups per router are kept. Works for MikroTik and OpenWRT-family routers; not yet verified against real hardware for either.
Scheduled reboot
A periodic maintenance restart on a schedule you set, found on each router's own Manage view (or applied to a whole Router group at once, under Network → Routers). Genuinely different from the outage alerting this platform already does — that only tells you when a router goes down unexpectedly; this actively restarts a healthy router on purpose, on the schedule you choose, using the exact same mechanism as the manual "Restart router" button.
Pick an hour (0-23, in SAST) and, optionally, specific days — leave every day unchecked for a daily reboot, or tick specific days for a weekly one (e.g. Sunday only, at 3am). A background check runs every 10 minutes and fires the reboot once it's inside the chosen hour, so it lands sometime within that hour rather than on the exact minute — fine for routine maintenance, not meant for split-second timing.
Applying a schedule to a whole Router group sets every router currently in that group to the same schedule in one action — it does not keep them linked afterward, so a router added to the group later needs the schedule applied again (the same one-time-bulk-apply behavior as that group's speed cap). Works for every router vendor this platform supports, since it rides the same restart mechanism already used for the manual button.
Fleet map
A live map of where your routers actually are, colored by whether each one is online right now, under Network → Fleet map. Built for an operator running many locations at once rather than one fixed site — particularly a vehicle fleet (buses, taxis), where the routers themselves move. Has its own search box (same smart search as Journey presets) to jump straight to a place instead of panning/zooming by hand.
How the location is worked out. Every router already reports its own public IP address on its normal check-in (the same mechanism the Abuse & IP complaints tool relies on). That IP is run through a free, offline IP-geolocation lookup — genuinely accurate to city/area level for a router sitting at a fixed location, shown as a plain dark dot. For a router on a mobile/cellular connection, such as an LTE dongle on a bus, this coarser IP-based method only resolves to wherever that connection is registered on the mobile network — not the vehicle's exact position, and it will not move in real time from IP alone. Where a router's agent actually supports GPS and is reporting a fresh fix (within the last 10 minutes), its real live position is shown instead, marked with a distinct blue ring so it visually reads as "genuinely live," and moves as the vehicle travels. Whether a given router supports GPS at all is auto-detected and shown in that router's Manage panel.
A router that hasn't reported a public IP yet (brand new, or not yet connected) has nothing to plot and is listed below the map instead of silently missing — it appears on the map itself the first time it checks in.
Many routers close together group into a single number badge (standard map-clustering, the same idea ride-hailing apps use to avoid a wall of overlapping icons) — click it to zoom in and see the individual routers split apart. Marker size also scales with zoom, smaller zoomed out and bigger zoomed in, so a country-wide view of a large fleet doesn't feel cluttered.
Your own location, and directions to a router. Allow location access when your browser prompts you, and your own position shows as a distinct blue marker on the map. Click any router's marker and use "Get directions" for a real driving distance, duration, and route line to it — worked out with your own GraphHopper key, the same one Journey presets uses for trip estimates. Without a saved key (or if a real route can't be found), this falls back to a straight-line distance and compass direction instead, so it's never a dead end.
RADIUS authentication (Advanced)
Collapsed under an "Advanced" section on the Routers page, off by default, and irrelevant to the vast majority of tenants — for an IT team that already runs its own RADIUS server (commonly tied to Active Directory) and wants this router to authenticate guests against it too. This is not a RADIUS server ISN operates for you; it's a way to point your own router's captive-portal login at a RADIUS server you already run, the same way the underlying open-source captive-portal software this platform builds on (chilli) has always natively supported.
Enter your RADIUS server's address, authentication port (default 1812), accounting port (default 1813), and shared secret — the secret is encrypted at rest and never shown back to you once saved; leaving it blank on a later save keeps whatever's already stored, the same convention Single Sign-On's own certificate field uses. Pushed automatically as part of Auto-config to OpenWRT-based routers and to MikroTik routers alike (MikroTik support is beta — see the Routers section above); any other router vendor needs this configured directly on the router itself. If your "own RADIUS server" is actually Cisco ISE, this is exactly how you connect it — ISE almost always already acts as a RADIUS server, so there's no separate Cisco-specific integration needed for that part.
Bandwidth & speed caps
Several separate speed caps exist across the dashboard, each governing a different scope — worth having in one place, since it's easy to set one expecting it to cover a case a different one actually governs. Default guest speed cap (Free access → Owner & guest access, Mbps down/up) applies to every regular guest at this location unless something more specific below overrides it — 0 means uncapped, no hidden platform ceiling underneath. Speed limit for each guest device, set from any router's own management page but — despite living there — applied account-wide across every router you run, not just that one, is the everyday version of the same idea: you pay your ISP for 150 Mbps but only want to hand each individual guest device 10 Mbps of it. Guests get full, uncapped speed the entire time they're actively watching ads to unlock or top up their ad-supported access — even one who already has an active bundle and its cap, going back to watch more — so an existing cap never fights with ad playback; the cap only re-applies the moment the new bundle actually lands. Your own owner-login session is never capped by any of this either. This router's total line speed, on that same router page, is a different and rarely-needed thing: a cap on that one specific router's own total incoming connection, for reserving bandwidth on a particular line rather than limiting individual guests.
Several more caps override the defaults above for a specific case: a data plan's own speed (sold at a certain price point, capped to match it), an internal account's own cap (0 falls back to the tenant default), a resident-issued guest voucher's visitor speed cap, the resident-guest-voucher fair usage policy's throttle speed once a resident's vouchers cross their monthly threshold, and the broader fair usage policy for all paid & earned access's own throttle speed (with its own optional per-plan/per-voucher/per-tier overrides) once any bundle crosses its rolling 24-hour threshold. In every case, 0 (or an empty field) means uncapped at that level, falling through to whichever broader default applies above it.
One thing no per-guest cap ever touches: traffic to your own captive portal itself — the login screen, Home, checking My Usage, buying a data plan — always loads at full speed, even for a guest whose general browsing is currently capped. A slow connection to your own portal would make it harder for a capped guest to buy more data or watch ads to top up, which defeats the point of capping them in the first place.
Every cap above is a fixed number you set once. Fair Share bandwidth is the alternative for a router where no single fixed number feels right for every crowd size — it automatically re-divides that router's real capacity evenly across however many guests are actually online at any given moment, instead of you picking one Mbps figure that's generous when it's quiet and not enough when it's busy.
Bandwidth cost forecast
Optional, off by default — if your ISP line has a monthly data cap, set it under Network → Routers alongside your monthly cost and which day your billing cycle starts on, and this projects whether you're on track to hit that cap before the cycle resets, based on real usage tracked at each router so far this cycle. A simple projection (your average GB/day so far, carried forward to the rest of the cycle), not anything more sophisticated — it's a heads-up, not a guarantee. Leave both fields blank to leave this off entirely; nothing is tracked or shown until you fill them in.
You'll get one email per billing cycle, the first time your projection crosses 75%, 90%, or 100% of your configured cap — not a repeat every day you're still over it. Turn it off entirely under Notifications (Bandwidth cost forecast) if you'd rather just check the dashboard yourself.
WiFi signal / coverage control
On each router's own management page, alongside its speed settings — reduces that router's WiFi broadcast power to keep coverage closer to your venue: dense buildings with shared walls or neighbouring shops, or simply stopping people outside on the street from connecting. This is a reduce-only control. Values are hard-capped at South Africa's ICASA license-exempt ceilings — 20 dBm (100 mW) on 2.4GHz, 30 dBm (1 W) on the common 5GHz WLAN bands (5150–5350 MHz and 5470–5725 MHz) — verified against the ICASA Radio Frequency Spectrum Regulations 2015, not assumed. You can never save a value above these, regardless of what the router's own hardware might technically support higher than that: staying under these ceilings is what keeps operation license-exempt in the first place, not a separate compliance step layered on top.
Leave either field blank to keep that radio at its own hardware default (full power) — nothing changes on a router until you actually set a value, and the two bands are independent (you can lower 2.4GHz while leaving 5GHz untouched, or vice versa). Automated for MikroTik (covers both RouterOS generations, since which one a given router runs isn't something we can detect in advance) and OpenWRT-family routers (Teltonika, GL.iNet, generic OpenWRT); not yet verified against real hardware for either.
Evil-twin / rogue access point detection
On by default for every router with a WiFi name configured — nothing to turn on, nothing to set up. Every 30 minutes, the router itself briefly scans the airwaves for nearby WiFi networks and checks whether a DIFFERENT device is broadcasting the exact same network name yours is configured to use. That's the standard "evil twin" attack: someone sets up their own access point using your hotspot's name (sometimes copying the login page too), so guests connect to them by mistake and everything they type goes straight to the attacker instead of you. If one is heard, you get an automatic email the moment it's detected — the same way a router going offline or a firewall tamper event already alerts you.
Worth being precise about what this does and doesn't do: it detects and alerts — it does not, and cannot, shut the rogue device down itself. No software running on your own network can reach out and silence someone else's radio; that's true of every WiFi security product, not a limitation specific to this one. What it actually fixes is the much more common failure mode: most evil-twin attacks succeed simply because nobody ever notices one is happening. Once you're alerted, the response is on you — walk the venue for an unfamiliar device, or escalate further if it doesn't stop.
A short (a few seconds) disconnect blip is possible for guests on the affected router during each scan — the radio briefly has to leave its own channel to listen for others, the same tradeoff real enterprise wireless-security hardware makes. That's why this runs every 30 minutes rather than the same 5-minute cycle as router-offline checks, and why each scan is kept short. A repeat sighting of the same rogue device only alerts once, not every 30 minutes it's still there — you'll be alerted again if it disappears and comes back later. Automated for MikroTik and OpenWRT-family routers; not yet verified against real hardware for either.
Remote CLI & restart
Direct command access to a paired router for diagnostics and one-off fixes, without needing physical or SSH access to the hardware yourself. Re-enter your dashboard password to unlock it, choosing how long the unlock should last (2, 5, 15, or 30 minutes) — after that it locks again automatically. Every command you run is logged with a timestamp, the router, the command itself, its status, and its output, kept as a permanent audit trail against your account, since this is the kind of tool that can take a whole site's WiFi offline if used carelessly. Restarting a router is a separate one-click action elsewhere (no CLI unlock needed) — expect it to be briefly unreachable, about a minute, while it comes back up.
Fair Pause & outage alerting
Two related things live in this one section: Fair Pause itself (protecting guest access time from outages), and NOC-style alerting so you actually find out about an outage as it happens, not from a guest complaint.
Outage alerting. The moment any router stops reporting in, and again the moment it comes back, you get an automatic email — the same "router offline"/"router back online" alert this platform has always sent, checked on a 5-minute cycle and sent only once per outage, not repeated every check while it's still down. Turn on "Also SMS me when a router goes offline or comes back online" below if email alone isn't reliably getting your attention — real NOC/ISP behaviour, using your own SMS credits, off by default since not every tenant wants an SMS for every blip. Every outage is logged in the "Outage history" table below (which router, when it went down, when it came back, how long it lasted, and how many guests had access time restored) — a durable record survives a server restart, so a redeploy mid-outage never causes a duplicate or missed alert for the same event.
Fair Pause protects guests from losing paid access time to something outside their control: when a specific router loses power or connectivity (load-shedding is the common case in South Africa, but any outage counts) and comes back later, any guest whose paid time-based access was tied to that exact router — and who still had time left when it went down — gets their access clock frozen for the length of the outage, then resumes exactly where they left off. A guest with 4 hours remaining when the power cuts, and a 3-hour outage, still has 4 hours remaining once it's back — not 1. This is scoped strictly to the one affected router; guests connected to your other routers are completely unaffected, even routers at the same site.
Data-bundle (MB) access needs no special handling and isn't affected by this setting either way — remaining data only ever decreases from bytes a router actually reports using, so a router that's offline physically can't report anything, meaning data usage already stops accruing on its own during an outage.
Covers ad-watch unlocks, purchased/redeemed vouchers, data-plan purchases, POS (till) sales, and API-granted access — anything that represents real revenue or genuine guest-earned access. Resident and internal-account-issued vouchers (the ones you or a landlord/manager hand out directly, not something a guest earns or buys) are deliberately excluded — this protects paying and ad-supported guests specifically, not every access grant on the platform.
Built-in protection against double-crediting: if an affected guest connects to a different one of your routers during the outage and keeps browsing there, they've already continued their session — when the original router comes back online, they don't also get time credited back on it. A guest who had nothing left when the outage started gets nothing back either, same as normal expiry.
On by default for every tenant; turn it off under this section if you'd rather access simply expire on schedule regardless of router outages. Detection rides the same outage check used elsewhere in the platform, on a five-minute cycle — so the credited freeze time can run a few minutes short of the true outage length, never longer. On a load-shedding-length outage that's a rounding error, not something a guest would notice.
Bandwidth congestion alerts
A genuinely different problem from a router going offline: this is a router that's UP but saturated — guests fighting over a pipe that's smaller than what's being asked of it, the plain ISP meaning of "congestion". Each router's real recent throughput (averaged over the last few minutes, not one instantaneous blip) is compared against its real capacity — preferring the router's own hourly ISP line speedtest (see Routers) where available, falling back to its configured router speed cap if not; a router with neither configured has nothing to measure against, so it's simply skipped rather than guessed at.
Cross 90% of that capacity and you get an automatic email naming the router, which direction is saturated (download or upload), the actual Mbps figure, and a suggestion (raise its cap, split load across a second router, or check who's using the most data). It won't fire again for the same ongoing event — usage has to drop back below 75% first (a deliberate gap between the alert and clear thresholds, so a router hovering right at the line doesn't flap between "alert" and "clear" every few minutes and spam you). Off/on toggle lives under Notifications, alongside every other alert type.
Fair Share bandwidth
A smarter alternative to a single fixed per-guest speed cap. Turn it on for a specific router (from that router's own settings, next to Total line speed) and, once 2 or more guests are actually connected to it, its real capacity is automatically re-divided evenly among however many are online right now — recalculated roughly once a minute. With only 2 guests on, each can burst to roughly half the pipe; the moment a 10th guest joins, it re-splits into 10 shares automatically. This is the same idea behind MikroTik's own PCQ (Per Connection Queue) or the classic Linux SFQ (Stochastic Fairness Queuing) concept, but built at the platform level rather than as a native router feature — which is exactly why it works identically on every router vendor this platform already pushes a per-device speed cap to (MikroTik and the OpenWRT family alike), not only MikroTik.
Capacity to divide up follows the same precedence as congestion alerts: the router's own real ISP-line speedtest where available, otherwise its configured router speed cap. A router with neither set has nothing to fairly divide, so Fair Share simply has no effect on it until one is configured.
Fair Share only ever pulls a guest's speed DOWN toward the fair split — it never raises anyone above what they're already entitled to. A guest on a higher-tier data plan, or one whose fair-usage policy has already throttled them, keeps whichever of the two numbers is lower; it never overrides a plan's own cap upward. A guest who's currently fully uncapped — watching an ad to unlock access, or simply on a tenant that runs an unlimited network by default — is left alone entirely rather than having a cap forced onto them, since that would break an existing guarantee elsewhere on the platform (see Bandwidth & speed caps). As soon as the router has headroom again (a guest leaves, or overall usage drops), any speed reduction Fair Share applied is released automatically on the next check — it's a live rebalancing act, not a permanent downgrade.
Off by default, per router — unlike Fair Pause, this actively changes a connected guest's live speed rather than just sending you a notification, so it's opt-in rather than on for everyone automatically. Worth turning on for a router that regularly has many guests competing for one line and no per-guest cap that feels right for every crowd size; less useful for a router that's rarely near capacity, since it has nothing to rebalance most of the time anyway.
Content filtering
Block specific websites on your WiFi. Nothing is blocked until you turn something on yourself — every option here starts off. Type the domains you want blocked, one per line, re-enter your password the same way as Remote CLI, and save; the rule pushes automatically to every router in your fleet that supports it, applying as soon as each one next checks in. Routers that aren't yet automated for filtering get a manual instruction instead: add a DNS blackhole entry for each domain, and drop the relevant ports at the firewall if you also want VPN mitigation. Speaking of which, an optional "VPN mitigation" toggle blocks common VPN ports and known public DNS-over-HTTPS providers — a genuine deterrent against casual VPN use, not an absolute guarantee; a sufficiently determined, technical user can still find a way around any network-level filter, true of every vendor's product, not just this one.
Three one-click category toggles — adult content, gambling, malware & phishing — save typing domains out by hand for the common cases. Each is a starter list (roughly 150 known domains, sourced from a maintained open-source blocklist) rather than an exhaustive database — genuinely useful, not a claim to catch everything. Category domains combine with anything you type manually, capped at 500 domains total per router (the same ceiling manual entries alone already had) so a router's own DNS resolver never gets asked to hold more than it reasonably can.
Protect minors from adult content is a different kind of rule from everything above it on this panel: those apply to every device on the router equally, this one targets WHO is browsing. Turn it on and set an age (default 18), and any guest under that age gets their device's DNS transparently redirected to a third-party family-safe resolver (CleanBrowsing) instead of the router's normal DNS — an adult guest on the exact same router at the exact same time is unaffected. It reads each guest's existing date of birth (the same field Dashboard home's age-restricted signup and age-targeted ads already use) — a guest with no date of birth on file is treated as under the limit until they provide one, the same fail-closed approach used elsewhere for age checks. Off by default, same as everything else on this panel. Automated for MikroTik (a self-expiring rule, refreshed for as long as the guest stays connected) and OpenWRT-family routers (Teltonika, GL.iNet, generic OpenWRT — a heavier push per guest since OpenWRT has no equivalent self-expiring mechanism, so it's refreshed less often and cleaned up automatically once a guest's device goes quiet); not yet verified against real hardware for either vendor family.
Allow extra domains before login (walled garden) — separate from blocking above, this is about what a guest can reach before they've even logged in. A fixed set of domains is always allowed pre-login on every router, automatically, and can't be turned off here: payment gateways (so a guest paying by card or QR to unlock never gets stuck mid-payment), known ad-hosting CDNs (so a video/image ad can actually load and play before someone's earned free access), and the handful of domains phones and laptops check to pop up the "sign in to this network" prompt in the first place. Type extra domains in the box at the bottom of this panel if your own setup needs something else reachable pre-login too — a custom ad network, an embedded booking widget — one per line, wildcards like *.example.com allowed. It's additive only: you can add to this list, but you can never remove or override the protected baseline, so this feature can't accidentally lock your own guests out of paying or unlocking. Saves and pushes to your routers the same way the rest of this panel does — no separate step. Automated for MikroTik and OpenWRT-family routers; not yet verified against real hardware.
Network topology
Built for bigger sites — hotels, malls, campuses — where one gateway router isn't the whole story: it's got a fleet of switches and access points behind it via a bridged LAN. Wiring-wise, nothing changes — guests are already caught by the gateway's own captive-portal redirect no matter how many switches or APs sit between them and it, as long as the network is properly bridged (same VLAN/subnet, trunk ports, APs backhauling to the gateway's LAN). What this adds is visibility: register each switch/AP under a "Network topology" section — its name, type, which gateway router it sits behind, an optional parent device if it's nested deeper (AP behind a switch, say), its LAN IP, and its SNMP read-only community string (SNMP is off by default on most switches/APs, so this is a real onboarding step, not just a form field — check the device's own admin page to turn it on and set a community string first). The gateway router's own agent does the polling — it's the only thing already on that LAN with a working channel back to the platform — walking each registered device over SNMP every 5 minutes for up/down status, latency, switch port traffic, and (best effort; AP client-counts are often vendor-proprietary rather than a standard MIB, so treat that number as approximate) connected client count, then relaying the results up the same way the existing ISP line speedtest already does.
The topology view is a simple indented tree — gateway at the top, its switches/APs nested underneath — with each device's status dot, and a health-score strip showing how many are online right now. Click into any device for its own 90-check uptime history (the same bar visualization used on the public status page) and, for switches, a per-port traffic table. One distinction matters here: a device shown gray with "no data" is different from one shown red as confirmed offline — gray means its own gateway router is currently unreachable, so the poller itself has nothing to report, not that the device is necessarily down; red means the gateway heard from it before and now can't. Offline alerts (opt in under Notifications, alongside the router-offline ones) follow the same logic — a switch/AP behind an already-alerted offline gateway won't also fire its own alert, since that's the gateway's alert to send, not two confusing emails for one outage.
Connect a controller (new, beta) skips manual per-device SNMP entry entirely for three ecosystems: UniFi, Omada, and Ruckus. Paste a UniFi Site Manager API key (generate one at unifi.ui.com under Settings → API Keys — this is Ubiquiti's own cloud API, so it works even if your console has no port-forward), an Omada Controller's Open API credentials (Settings → Platform Integration → Open API in the Controller — a different, more privileged credential than the one used for guest hotspot login), or a Ruckus SmartZone controller's own URL and admin login, pick which of your routers the discovered devices should nest under, and save. Every switch and access point the controller reports is discovered, added, and kept in sync automatically on the same 5-minute cycle as SNMP — no community string, no per-device form. A device the controller stops reporting (unplugged, removed from the site) is deactivated automatically rather than left stale, the same way a manually-removed device is. This is newly built and, unlike the SNMP path above, not yet verified against a real controller of any of the three — a wrong credential or endpoint fails as one clear sync error on this page rather than silently, and "Sync now" lets you check immediately instead of waiting for the next cycle. Ruckus covers access points only for now, not switches; for a SmartZone controller, the URL you paste needs to include the port and API base path your specific model/firmware uses (Ruckus publishes this per-version, not as one stable address).
Built for scale — ISPs, agencies & large deployments
Nothing on this page changes for a bigger operator — it's the same platform, just used at a different scale. My clients is the anchor for this: run WiFi for more than one site under one login, each one a fully isolated captive (its own branding, routers, vouchers, guest data — nothing bleeds between clients), with a franchise-style rollup of revenue and offline-router alerts across all of them so an operator running dozens of branches can see what needs attention at a glance instead of clicking into each one. Plan & pricing backs this up structurally, not just in the dashboard: unlimited routers and locations at no extra cost, ever — you're billed on peak concurrent users, never on how many sites or access points you've added, so growing the fleet never means renegotiating the bill.
Hardware breadth matters at this scale, since a large deployment is rarely one router vendor end to end: Routers lists what's fully automated today (MikroTik, Teltonika, GL.iNet, generic OpenWRT, Cisco Meraki, TP-Link Omada) alongside guided manual setup for everything else (Cisco WLC/ISE, Cisco small-business, Cambium, Ruckus, stock Cudy) — a mixed fleet from a multi-year rollout isn't a blocker, it's the expected case. For a site that's more than one gateway router — a hotel, mall, or campus with switches and access points behind it — Network topology gives fleet-wide visibility (up/down status, latency, per-port traffic, client counts) without extra hardware. And if your organization already runs its own RADIUS server tied to Active Directory or Cisco ISE, RADIUS authentication connects a router to it directly — this platform fits into infrastructure you've already built, rather than asking you to replace it.
The operational side scales the same way: Team members gives every person on a large staff exactly the access their job needs (with a genuine server-side enforcement, not a hidden menu), and an owner can grant one invite access across every captive they run instead of re-inviting the same person site by site. The Partner API lets your own booking, POS, or provisioning systems issue vouchers or grant access directly and safely at volume — idempotent by design, so a retry after a network blip never risks a duplicate charge or a duplicate grant. None of this asks for a steeper learning curve than a single-site setup: adding a router is still one SSH command and an auto-config wizard, every role signs in with the one email/password that already works across every dashboard it has access to, and a router vendor without full automation still gets guidance written for that specific hardware rather than a generic fallback — the same plain, no-surprises design whether you're running one venue or a hundred.
Insights
Everything you need to understand who's using your WiFi and how — from the big-picture trend line down to a single guest's history.
Analytics & reports
The aggregate picture over a range you choose (7/30/90 days): guest connections, peak concurrent devices, ad views and clicks by campaign, vouchers redeemed, and SMS sent — with a downloadable CSV report. Guest connections count real portal activity (every ad-unlock, voucher redemption, data-plan purchase, or free-access grant), so it stays accurate even for a location whose router isn't yet reporting live telemetry. Peak concurrent devices prefers real router-reported device counts for its daily trend; if a router hasn't reported any data for the period, the summary figure falls back to your accurate monthly peak (the same number shown in Plan & pricing) rather than showing a misleading zero next to genuinely non-zero activity elsewhere on the page. A "Busiest hours" heatmap breaks the same connection events down by hour and day of week (South African time), so you can see when guests actually show up, not just how many. Below it, a capacity forecast turns your router-reported concurrent device counts into an actual recommendation — if any day of the week is trending close to your concurrent user limit, it says so directly (e.g. "trending toward your limit on Saturdays") instead of leaving you to read the trend off a chart yourself; needs at least one router actively reporting to appear at all. The stats grid also includes an average guest download/upload speed for the range — an estimate of what a connected guest actually experienced (router throughput divided by how many devices were online at each sampled moment), separate from any cap you've configured, so you can tell whether a slow week is your own settings or your ISP underdelivering.
A "Footfall & repeat visitors" panel answers "who's actually visiting my venue," beyond just how much data was used: unique visitors for the range, how many are brand new versus coming back, a returning ratio, and the single busiest hour (derived from the same heatmap above). A guest counts as returning if they connected at all before the start of your selected range — going further back than the range itself, not just within it, so a monthly regular still shows as returning even on a 7-day view. One thing deliberately left out: a "time spent on site" figure. There's no reliable way to measure that today — a voucher's or bundle's configured duration is how long access is valid for, not how long the guest actually stayed, and building a real one needs session-level tracking this platform doesn't do yet, so rather than show a number that would just be wrong, it's left out until it can be done honestly.
Guest activity
The individual event log, for when you need to trace one specific guest or incident rather than the aggregate trend: registered users (name, email/phone, bundle and remaining data, status, when they registered), recent bundle-grant transactions (identifier, bundle size, router, when granted), and domain visits — POPIA-compliant, daily anonymised snapshots aggregated by domain only, never a per-guest browsing history.
Notifications
Everything that needs your attention, surfaced by email in one place instead of you having to notice it yourself in the dashboard: low SMS credits (and, if you've set one, your monthly auto-topup spend cap being reached), capacity approaching and capacity-reached warnings (your billing/concurrent-user ceiling — see Plan & pricing), bandwidth congestion alerts (real Mbps saturation on a specific router — a different thing from the capacity warnings above; see Bandwidth congestion alerts), billing reminders sent a few days ahead of a trial converting to paid or a subscription renewing so a charge is never a surprise, a router offline alert the moment any router in your fleet stops reporting in (checked every 5 minutes, and only ever sent once per outage — not repeated every check while it stays down, with an opt-in SMS version too — see Fair Pause & outage alerting), and an optional weekly summary — revenue, guest connections, busiest hour, and SMS balance, sent every Monday morning. Each type can be switched off individually if you'd rather not receive it. Every one of these is sent to your own account's registered email — never anyone else's, and never shared across tenants.
Security alerts
Automatic anomaly detection for internal accounts and roaming logins, tenant-scoped, surfaced as a live feed you can review from the dashboard. Three signals feed it: impossible travel (the same account authenticating from two locations too far apart to genuinely be the same person, inside too short a window), excessive device cycling (one identifier moving through an unusually high number of distinct devices in a day — the pattern a shared or leaked login produces, not normal multi-device use), and a general credential sharing detected signal covering related patterns.
These are signals, not an enforcement gate — nothing is auto-blocked or auto-logged-out when one fires, since a legitimate case (a phone and a laptop, a household sharing one account) can still occasionally brush against the same thresholds. An alert is something to review and act on yourself — reset the account's credentials, tighten its device limit, or reach out to whoever it belongs to — rather than something the platform decides on your behalf.
Abuse & IP complaints
A log-and-lookup tool for the question every network operator eventually has to answer: "who was actually using this IP at this reported time?" Log a report with the IP address involved, when the activity was reported to have happened, a description, and (optionally) who reported it — then click "Look up" to have the platform find the answer from data it already has: which of your routers actually had that public IP at that exact moment, and which of your guests had a live, granted access session on that router at the same time.
How the lookup actually works. Every router already reports its own real public IP address to us on its normal check-in (the same IP any outside party sees when your router talks to the internet) — we keep a full history of this per router, not just the current value, specifically because a complaint often lands days after the fact, by which point a dynamic IP may have already changed. The lookup matches the reported IP and time against that history to find the router, then cross-references that router's own granted-access log for guests who were online at that exact moment. If your router's IP hasn't changed since the reported time, this resolves cleanly; if it has changed more than once since, or the router wasn't registered with us yet at that time, there may be nothing to match — the tool tells you either way rather than guessing.
What this deliberately is not. It's an operational log and a lookup tool, not a legal-advice generator — it doesn't draft a takedown notice, cite a specific law, or tell you what you're obligated to do with a complaint once you've resolved it. Legal requirements around network-abuse complaints vary by jurisdiction and by what's actually being alleged; for that part, talk to your own legal advisor rather than relying on anything generated here.
Banned devices
Blocks a specific device's MAC address from your WiFi entirely, for cases like the abuse tool above turning up a repeat offender. Found under Security → Banned devices. Enter the device's MAC address, an optional reason for your own record, and choose whether the ban applies to just one of your routers or across your whole fleet at once. An already-connected device is also kicked off immediately as part of the same action.
Enforced at the router itself, not just in this dashboard. A ban pushes a real block rule to the router — a MikroTik hotspot IP-binding marked "blocked", or an OpenWRT firewall rule dropping that MAC's traffic — so the device genuinely cannot reach the network, rather than this platform trying to recognize and refuse it at every single one of the different ways a guest can get online here (voucher, ad-unlock, point-of-sale, SSO, roaming). A block at the router is the one mechanism that automatically covers all of those at once, because the device never gets anywhere near any of them.
A fleet-wide ban is pushed to every router you have at the moment you set it; a router you add afterward does not automatically inherit existing bans yet — re-ban from this page if you want it to also apply to a brand-new router. Works for MikroTik and OpenWRT-family routers; not yet verified against real hardware for either.
Data retention (POPIA auto-purge)
Off until you set a window (a blank/empty value leaves it off — there's a 30-day floor once you do turn it on, enforced regardless of what's entered, so a mistaken tiny value can't purge near-fresh data). Once configured, a daily check anonymizes the record of any guest who hasn't logged in for at least that long — clearing their name, date of birth, email, phone, and registration IP/device info. Their past usage and revenue totals stay exactly as they were in your reporting; only who they were is cleared, not what they did.
Worth knowing the real scope: this clears the guest's main identity record, but doesn't yet reach into every historical row elsewhere on this platform that separately stored their contact details (e.g. an old voucher redemption log) — a real, working purge of the primary record, not a claim of scrubbing every last trace. A guest who returns after their record was purged simply signs up again as new. A "Purge history" table below the setting shows every run — how many records, and what window was active at the time — for your own compliance record.
Privacy requests (POPIA)
South Africa's Protection of Personal Information Act gives every guest two rights this handles for you: to see the personal information you hold about them (section 23), and to ask for it to be deleted (section 24). Find it under Security → Privacy requests. Only the account owner and the IT Department role can open it, since it hands over or removes a real person's data.
How guests use it. A guest already signed in to your WiFi finds Download My Data and Delete My Data right in their own My Account panel, next to their profile, including from the link in your own guest terms (section 8) — no separate page or re-typing their number/email, just their password once to confirm it's really them. Download My Data gives them a file straight away with their profile, data bundles, purchases, vouchers, devices, sign-ins and ad activity. It's logged in your list as done, with nothing for you to action. Delete My Data lands in your list as "Waiting on you" with a due date 30 days out, and you get an email about it. This is the same check your WiFi login already uses, with the same lockout after repeated wrong guesses, and a guest can only ever see or request their own data. A guest who isn't currently signed in has nothing to check a password against, so they're prompted to log in first — the same as opening any other part of My Account.
What "Delete now" actually does. The guest's name, email, phone, date of birth, password and sign-up details are cleared. Their devices are signed off the network and removed. Ad views, ad clicks and visit history are kept for your ad billing totals but no longer point to the person (the IP address and browser details are cleared too). Connection and billing records (sign-ins, data used, bundles, purchases, vouchers, till grants, roaming) are kept, because RICA requires them for 5 years. This matches what your captive's terms already tell guests, and the guest is told the same thing when they ask. If any part fails, nothing is marked complete, so you can simply press it again. For a staff or student username account, the login itself stays in Internal accounts for you to disable there.
Other options. Download data gives you the same file the guest would get, for a request that came in by email or at the front desk. Refuse closes a request with a reason, which POPIA requires. A lawful reason might be an unpaid account or a legal hold. Log a request for a guest records a request made in person, by phone or by email. Confirm it's really them first. Once a request is closed, the guest's actual number or email is removed from the request itself, and only a masked version (e.g. 082****567) stays in your records.
Team & access
Invite staff with exactly the access they need instead of sharing one login, and let your own systems talk to ISN Free WiFi directly.
Team members
Invite someone by name, email, and role — they get an email with an activation link to set their own password, never yours. Five roles are available: IT Department (full access, both this dashboard and your captive's own dashboard), Full Admin (full access, captive dashboard only), Ads/Marketing Manager (ads, vouchers, branding, and routers, on the captive dashboard), Financial (billing and invoices only), and View Only (read-only everywhere it can see; any attempted change is blocked). Every role is enforced on the server, not just hidden in the menu — a Financial-role login genuinely cannot reach voucher generation even by guessing a URL, and a View Only login genuinely cannot save anything. By default an invite only covers this one captive; check "Give access to every captive I own" (owner-only) to extend it across every client you run. Only the account owner and IT-role members can manage the team roster itself — the owner's own role can never be changed or removed by anyone.
API & integrations
Generate an API key here to issue and reschedule vouchers, or grant WiFi access directly, programmatically from your own booking system or point-of-sale — vouchers always issue against a voucher preset you've already defined, so bundle, price, and duration stay under your control no matter what the calling system sends. Every key is shown to you once at creation; only a hash is stored afterward, so losing it means generating a new one, not recovering the old. Never call this API from browser or front-end code — a page's JavaScript, a Wix page, or a WordPress theme's front-end script is visible to every visitor, and a key is a live credential worth money, not "sort of secret" like a session ID. Always call it from a server you control.
Base URL & authentication — send your key on every request as the x-api-key header (it starts with isn_live_). The key alone determines which of your captives a request belongs to; the hostname you call doesn't need to match that captive's own domain.
POST /api/partner/vouchers/issue | Issues one new voucher against a preset. Safe to retry: calling it twice with the same externalReference never issues a second voucher — it returns the same one again. Against a Journey-based (per-stop) preset, price/duration/router-restriction all come from that preset automatically. Against a plain preset, optionally pass journeyPresetId plus journeyStopIndex to resolve a specific route stop's fare and duration dynamically instead. |
|---|---|
POST /api/partner/vouchers/reschedule | Changes the expiry date of a voucher you've already issued that hasn't been redeemed yet, identified by that same externalReference. |
POST /api/partner/wifi/grant | Grants WiFi access to a guest identifier (phone or email) immediately, against a preset — no code for the guest to type in. Built for a till/POS system: the guest pays, your system calls this, they're online. Also safe to retry with the same externalReference. |
externalReference is the idempotency key for both issuing and granting — derive it from something already unique in your own system (an order, booking, or till transaction ID), never a random value per attempt, so a retry after a network timeout safely returns the original result (HTTP 200) instead of risking a duplicate grant (HTTP 201, which only fires the first time). Grants are checked against your location's concurrent-guest limit and a daily-cap on the key itself (lower by default than voucher issuance, since a grant is live bandwidth immediately rather than a dormant code) — see the Integration guide button on the API & integrations tab of your dashboard for full request/response shapes and code samples in six languages.
Send a phone number however your own system has it — you don't need to format it first. POST /api/partner/wifi/grant's identifier field accepts a South African phone number in any common shape (0821234567, 082 123 4567, +27821234567, 27821234567, or the international-dialling form 0027821234567) or an email address, and normalizes it to the exact same internal form this platform already uses everywhere else — the guest's own login, their usage history, fair-usage tracking, everything. This matters in practice: if your system and a guest's own phone happen to store the same number differently, a grant sent in your format still lands on that guest's real, existing account instead of quietly creating a second, disconnected one.
Node.js 18+ (built-in fetch, no extra dependency). Keep ISN_API_KEY in an environment variable, never hard-coded.
const ISN_API_KEY = process.env.ISN_API_KEY; // isn_live_...
const ISN_BASE_URL = 'https://isnfreewifi.co.za'; // any domain that reaches this server works -- see "Base URL & authentication" above
async function issueVoucher(presetId, externalReference, ticketDate) {
const res = await fetch(`${ISN_BASE_URL}/api/partner/vouchers/issue`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-api-key': ISN_API_KEY },
body: JSON.stringify({ presetId, externalReference, ticketDate })
});
const data = await res.json();
if (!data.ok) throw new Error(data.message);
return data; // { code, bundleMB, durationHours, price, expiresAt, ... }
}
// Example: issue a voucher right after a booking is confirmed
issueVoucher(12, 'BOOKING-90142', '2026-08-10')
.then(v => console.log('Voucher code:', v.code))
.catch(err => console.error('Issue failed:', err.message));
Python 3 with requests (pip install requests). Keep ISN_API_KEY in an environment variable, never hard-coded.
import os
import requests
ISN_API_KEY = os.environ["ISN_API_KEY"] # isn_live_...
ISN_BASE_URL = "https://isnfreewifi.co.za" # any domain that reaches this server works -- see "Base URL & authentication" above
def issue_voucher(preset_id, external_reference, ticket_date=None):
response = requests.post(
f"{ISN_BASE_URL}/api/partner/vouchers/issue",
headers={"Content-Type": "application/json", "x-api-key": ISN_API_KEY},
json={"presetId": preset_id, "externalReference": external_reference, "ticketDate": ticket_date},
timeout=15,
)
data = response.json()
if not data.get("ok"):
raise RuntimeError(data.get("message", "Unable to issue voucher"))
return data # {"code": "AB12-CD34", "bundleMB": 1000, ...}
# Example: issue a voucher right after a booking is confirmed
voucher = issue_voucher(12, "BOOKING-90142", "2026-08-10")
print("Voucher code:", voucher["code"])
Plain PHP with the built-in curl extension — for a non-WordPress backend. Running WordPress instead? Use the WordPress tab, which uses wp_remote_post and hooks into your site the WordPress way.
<?php
$ISN_API_KEY = getenv('ISN_API_KEY'); // isn_live_...
$ISN_BASE_URL = 'https://isnfreewifi.co.za'; // any domain that reaches this server works -- see "Base URL & authentication" above
function isn_partner_api_call($url, $apiKey, $body) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'x-api-key: ' . $apiKey],
CURLOPT_POSTFIELDS => json_encode($body),
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
$voucher = isn_partner_api_call($ISN_BASE_URL . '/api/partner/vouchers/issue', $ISN_API_KEY, [
'presetId' => 12,
'externalReference' => 'BOOKING-90142',
'ticketDate' => '2026-08-10',
]);
if (empty($voucher['ok'])) {
throw new Exception($voucher['message'] ?? 'Unable to issue voucher');
}
echo 'Voucher code: ' . $voucher['code'];
Handy for a quick manual test from a terminal before wiring up real code.
curl -X POST https://isnfreewifi.co.za/api/partner/vouchers/issue \
-H "Content-Type: application/json" \
-H "x-api-key: isn_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"presetId": 12,
"externalReference": "BOOKING-90142",
"ticketDate": "2026-08-10"
}'
curl -X POST https://isnfreewifi.co.za/api/partner/vouchers/reschedule \
-H "Content-Type: application/json" \
-H "x-api-key: isn_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"externalReference": "BOOKING-90142",
"ticketDate": "2026-08-14"
}'
Add to your theme's functions.php (or a small custom plugin — safer, survives theme updates). Define the key once in wp-config.php, outside the web root's publicly-served files.
// wp-config.php
define( 'ISN_API_KEY', 'isn_live_xxxxxxxxxxxxxxxxxxxxxxxx' );
// functions.php
function isn_issue_wifi_voucher( $preset_id, $external_reference, $ticket_date = null ) {
$response = wp_remote_post( 'https://isnfreewifi.co.za/api/partner/vouchers/issue', array(
'headers' => array(
'Content-Type' => 'application/json',
'x-api-key' => ISN_API_KEY,
),
'body' => wp_json_encode( array(
'presetId' => $preset_id,
'externalReference' => $external_reference,
'ticketDate' => $ticket_date,
) ),
'timeout' => 15,
) );
if ( is_wp_error( $response ) ) {
error_log( 'ISN voucher issue failed: ' . $response->get_error_message() );
return null;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $body['ok'] ) ) {
error_log( 'ISN voucher issue rejected: ' . ( $body['message'] ?? 'unknown error' ) );
return null;
}
return $body; // ['code' => 'AB12-CD34', 'bundleMB' => 1000, ...]
}
// Example: issue a voucher when a WooCommerce order is marked completed
add_action( 'woocommerce_order_status_completed', function ( $order_id ) {
$order = wc_get_order( $order_id );
$voucher = isn_issue_wifi_voucher( 12, 'ORDER-' . $order_id );
if ( $voucher ) {
$order->add_order_note( 'Wi-Fi voucher issued: ' . $voucher['code'] );
}
} );
No WooCommerce? Hook isn_issue_wifi_voucher() into whatever action your booking plugin fires on confirmation (Bookly, Amelia, Gravity Forms' gform_after_submission, etc.) the same way.
Wix page code runs in the visitor's browser, so the key must live in a Velo backend file (backend/isnWifi.jsw) instead, ideally pulled from the Wix Secrets Manager rather than hard-coded even there.
// backend/isnWifi.jsw
import { fetch } from 'wix-fetch';
import { getSecret } from 'wix-secrets-backend';
export async function issueWifiVoucher(presetId, externalReference, ticketDate) {
const apiKey = await getSecret('ISN_API_KEY'); // stored in Secrets Manager
const response = await fetch('https://isnfreewifi.co.za/api/partner/vouchers/issue', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
body: JSON.stringify({ presetId, externalReference, ticketDate })
});
const data = await response.json();
if (!data.ok) throw new Error(data.message);
return data;
}
// e.g. Bookings page code, on a "booking confirmed" event — never call the
// API straight from page code with the key inline, always via this backend file.
// import { issueWifiVoucher } from 'backend/isnWifi.jsw';
// issueWifiVoucher(12, 'BOOKING-' + booking._id)
// .then((voucher) => console.log('Voucher issued:', voucher.code))
// .catch((err) => console.error('Voucher issue failed:', err.message));
| 400 | Missing/invalid presetId, externalReference, or ticketDate. |
|---|---|
| 401 | Missing, malformed, or unknown API key. |
| 403 | Key revoked, or the account is suspended for billing. |
| 404 | Preset not found/inactive, or (reschedule) no matching unused voucher for that reference. |
| 409 | That reference was already issued against a different preset. |
| 429 | Rate limit or daily issuance cap reached — back off and retry later. |
Every response includes {"ok": false, "message": "..."} on failure — always check ok rather than assuming a 200-range status means success. The Integration guide button inside the dashboard opens this same reference with your own domain already filled in, plus a live key-generation form.
Webhooks
The opposite direction from the API above: instead of your system calling ISN, ISN calls a URL on your own server the moment a real event happens, so your booking system, CRM, or POS hears about it immediately instead of having to poll this dashboard. Set one up from API & integrations → Webhooks — a URL (must start with https://) and which events to receive. Owner-only: no other team role, including Financial or IT, can create, edit, or delete a webhook, since it's effectively a credential plus a live feed of guest activity.
Events available today: guest.signup (fires right after a guest completes registration), voucher.redeemed (fires the moment a voucher is redeemed), router.offline and router.online (fire on the same detection this platform already uses for its own outage email/SMS alerts). Up to 10 webhooks per captive, each subscribed to whichever of those you pick.
Verifying a delivery. Every request is a POST with a JSON body shaped {"event", "id", "createdAt", "data"}, plus three headers: X-ISN-Event (the event type), X-ISN-Delivery (a unique ID per attempt, for your own de-duplication), and X-ISN-Signature — an HMAC-SHA256 of the exact raw request body, signed with the webhook's own secret. Recompute that same HMAC over the raw body on your end and compare it to the header before trusting the payload; this is what proves a request genuinely came from ISN and wasn't sent by anyone who simply found your URL. The secret is shown to you exactly once, right when you create the webhook — copy it immediately, since only a hash of it is stored afterward; losing it means deleting the webhook and creating a new one, not recovering the old secret.
Delivery behavior. A delivery must respond 2xx within 5 seconds to count as successful; anything else — a timeout, a non-2xx status, or a connection failure — is retried up to 3 times with a short backoff between attempts. A webhook that fails 20 times in a row is automatically disabled (re-enabling it from the dashboard clears that failure count and gives it a clean slate) so a permanently broken endpoint doesn't get hammered forever. The "Test" button sends a real sample delivery on demand to check your receiver end-to-end before relying on it — deliberately capped at 20 tests/hour per account, tighter than the rest of the dashboard, since it makes ISN's own server originate a request to a URL you control. Every delivery attempt, successful or not, is logged with its HTTP status and timestamp right under that webhook in the dashboard, so a silent failure on your end is visible without needing your own server logs.
A webhook URL is checked for safety both when you save it and again at the moment of every single delivery — the same "not a private/internal address" check used elsewhere on this platform — specifically because a URL that was a genuine public address when you first set it up could theoretically be re-pointed at an internal one later, and that re-check exists to catch that rather than trusting the URL forever just because it looked fine once.
Account
Your own login and identity — separate from any single captive's branding, and shared across every captive you run.
My profile
Your login email (display-only here — changing it goes through a separate, security-question-gated recovery flow, not this form), your full name, phone number, company name, and a "person responsible" contact if that's someone other than you — used for billing contact and support, never shown to your guests. A separate section changes your password (current password required), and an optional but recommended "security questions" section lets you set at least 3 questions so, if you ever lose access to your own email and can't sign in, ISN support can verify it's really you before changing your login email — support never asks for or uses your password to do this.
Two-factor authentication (authenticator app)
Every owner login already requires a second step by default — a 6-digit code emailed to you after your password. This adds an alternative: a code from an authenticator app (Google Authenticator, Authy, or any standard TOTP app) on your phone instead, for anyone who'd rather not depend on email at sign-in. Turn it on from "My profile" → "Two-factor authentication" — you'll scan a QR code (or type in a short manual key if you can't scan), then confirm with the 6-digit code the app shows you. Once confirmed, you're also given 8 one-time backup codes, shown exactly once — save them somewhere safe, since each one gets you back in exactly once if you ever lose the phone the app is on. From then on, signing in asks for the authenticator code instead of an emailed one (a "use a backup code instead" link is right there if you need it); your password and everything else about signing in stays the same. Turning it off again asks for your current password first, same as changing your password does, and immediately goes back to emailed codes — nothing else changes. This only applies to the account owner (the one who created the captive); team members keep using their emailed code as-is.
This covers signing in here, at isnfreewifi.co.za. If you also use the older, separate business-dashboard.html on your own captive domain (a completely different login system), it now has the exact same two-factor protection — emailed code by default, the same authenticator-app option under its own Settings — but it's a separate login with its own password and its own "Two-Factor Authentication" toggle; turning this one on or off has no effect there, and vice versa. Its emailed codes come from your own configured sender if you've set one up (see Email settings); otherwise from the same default ISN Free WiFi sender this one uses.
Lost the device an authenticator app was on? If it's one of your own team or advertiser accounts on business-dashboard.html, an admin can turn their 2FA off directly from Business Accounts — no need to contact us. If it's your own login (the account owner, here or on business-dashboard.html) that's locked out, email info@isnfreewifi.co.za and ISN support will verify it's you and disable it for you.
Switch captive
Every branded location on your login, one click away — the same list shown in the account menu in the header, just easier to find here. Click any other captive in the list and your session switches into it instantly, no re-entering a password. "Add another captive" starts a brand-new one under this same login without leaving your current session (subject to the same 2-captives-until-first-payment limit described under My clients).
The ISN website
Everything above this line documents what happens after you've signed up. This section documents the site you're on right now — isnfreewifi.co.za itself — for anyone trying to understand what each part of it is for, whether that's a prospect evaluating the platform or an existing tenant trying to find where something lives.
Home
The homepage (isnfreewifi.co.za, no path) is the pitch, aimed at whoever's evaluating whether to run their guest WiFi on ISN instead of a vendor's stock hotspot app or nothing at all. It opens on what the platform actually is — a SaaS company you subscribe to and keep getting updates from, not a box you buy once and are stuck with — then walks through what running a captive on ISN gets you: real router management instead of a vendor-locked app, monetization options so guest WiFi can pay for itself instead of only costing money, and the infrastructure and scale claims behind that. If you've read this far into the documentation, you already know the platform in more depth than the homepage goes into — it's written for people who haven't signed up yet, not as a reference for people who have.
Features
Where the homepage sells the idea, Features is the technical follow-through for someone doing real evaluation: router fleet management that isn't just a read-only status page but real, audited shell access to your own hardware (the same capability documented in depth under Network → Remote CLI & restart above); the monetization options in more depth (Vouchers); custom domains (Branding → Custom domain); named accounts sitting alongside open guest access (Free access); SMS built into the platform with no separate provider account to configure (Messaging); and strict tenant isolation. Every claim on this page is something this documentation covers in full once you're actually running a captive, not marketing exaggeration.
Solutions
A by-industry version of the same pitch, because "guest WiFi platform" means something different to an airport than it does to a 40-bed student residence. Each industry — Airports, Education, Hotels and Hospitality, ISPs, Marina, Public spaces, Restaurants and Cafes, Retail, and Transport — gets its own anchored section (e.g. /solutions#education) written around what that kind of venue actually needs from guest WiFi, closing on the same point every section makes: it's the same platform underneath for all of them, just configured differently — the same dashboard and features this documentation covers apply regardless of which industry brought you here.
Resources
The catch-all for everything that isn't a sales pitch: About Us (the company itself), the Help Center (short answers to the questions people actually ask), this Documentation page (the full reference), News & Updates (a running changelog of what's shipped), and System Status (see below). The footer's Resources column adds a few more: a head-to-head comparison page against alternatives like Powerlynx and MikroTik's own hotspot tooling, and the legal set — Terms & Conditions, Service Level Agreement, Privacy Policy, and Security — covering the contractual, uptime, data-handling, and security commitments behind the platform, respectively.
Pricing
One plan, not a tiered ladder to climb — R1,500/month covers 300 concurrent connected guests, unlimited routers and locations at no extra cost, with extra concurrent users beyond 300 billed at R5 each. An interactive calculator on the page lets you estimate your own monthly cost by entering an expected concurrent-guest number before you ever sign up. These are the exact same figures — and the exact same "peak concurrent users this month decides what you pay" logic — documented in full once you're a tenant under Billing & plan → Plan & pricing; nothing changes between what's quoted here and what you're actually billed.
ISN status
Not a static "all good" badge — this page shows what's actually running right now, any scheduled maintenance, active incidents, and a rolling uptime history per monitored component. It reports on ISN's own infrastructure — the platform every tenant runs on — not any individual tenant's own router or captive uptime, which is what that tenant's own Status Page (covered below) is for.
Two addresses, on purpose: isnfreewifi.co.za/status is a page inside the main app itself — quick to reach, but if the main app ever goes down, this page (and its data) would go down with it, which defeats the point of a status page. status.isnfreewifi.co.za is a completely separate, independently-deployed service that watches the main app from the outside over plain HTTPS, the same way a visitor or an uptime monitor would — so it keeps working, and keeps showing the outage, even while the main app itself is offline. It has its own copy of the sensor checks and its own logo/styling baked in rather than borrowed from the main site, specifically so nothing about it depends on the main app being reachable. If you only bookmark one, bookmark status.isnfreewifi.co.za — it's the one that's actually useful during an incident.
Color-coded header, so you don't have to go looking: whenever a maintenance window or incident is scheduled or underway, the site header itself picks it up — a pulsing amber border and a compact "Read more" pill mean it's planned (a heads-up for something coming up), and the same treatment in a hotter orange means it's active right now. This isn't limited to the marketing site: the exact same color-coded pill appears in your own ISN Dashboard header, and the equivalent banner shows on your captive's guest-facing home page and on your captive's own Captive Dashboard — so anyone looking at any of those screens gets the same heads-up without needing to already know to check Status first. Clicking "Read more" jumps straight to the relevant status page; the header reverts to normal on its own the moment the window or incident is marked resolved.
Login & signup
The header's Login and Get started buttons are for becoming or managing an ISN tenant account, not for a guest joining someone's WiFi — an important distinction, since the platform also has a completely separate login screen guests see on the captive itself (covered below), and the two are never interchangeable. Signup collects a business name, an owner name and email, then a short set-up flow — confirm your email and set a password, then brand it with a logo, colors, and your first router — before you land in the dashboard this documentation spends most of its time on.
The captive portal
Everything from here documents what your own guests — not you — actually see and click through when they join your WiFi. Understanding this flow makes the dashboard settings above easier to reason about, since most of them (branding, vouchers, free access, content filtering) are really just configuring what happens at these exact screens. A guest's device gets redirected here automatically by your router the moment it joins the network and tries to browse; none of these pages are something a guest goes looking for by URL.
Captive Login
The actual WiFi login/signup screen (login.html) — your router's External Login URL (set under Network → Routers) points here, and it's what actually loads your branding & colors rather than a generic template. A guest enters a South African phone number or email, verifies with a one-time SMS/email code (drawn from your SMS balance), and picks how they're getting online — watching an ad, redeeming a voucher, or paying for a data plan, depending on which of those you've switched on under Vouchers. An "already connected on another device?" option lets a guest link a second device to the same active data grant instead of starting a fresh one from zero.
Home
The screen a guest lands on once they're actually online (home.html) — not a dead end, but their ongoing hub for the rest of the session. This is where the My Usage panel lives: remaining data, remaining time, and (for ad-supported access) a live-updating ad-watch counter for topping up with more. For a guest signed in through an internal account, SSO, or roaming, an additional My Account area appears — covered next. Everything a guest does after their first successful login — watching another ad, checking how much data is left, seeing when access expires, or generating a guest voucher — happens on this one page, not a series of separate screens.
If you've set up subscription plans, "Buy Internet Access" lists them in their own clearly-labelled group, separate from one-off vouchers and data plans, so a guest can tell at a glance they're starting a recurring plan rather than a single purchase. A guest with an active subscription also gets a "Your subscription" section inside My Usage — plan name, status, next billing date, and a "Cancel subscription" button for stopping future renewals themselves, without needing to contact you (see Recurring billing, retries & cancellation).
Bundles generated from a journey preset (one row per stop along the same route) show grouped under their route's own name, in a bordered box, in stop order — both in "Buy Internet Access" and in "Use my balance instead" — instead of appearing as a flat list of similarly-named, seemingly-unrelated bundles. A plain (non-journey) bundle is shown exactly as before, outside any group.
My Account
A self-service panel for a guest signed in through an internal account, SSO, or roaming — their own usage, a list of every device currently signed in on their account, and, if they're roaming, where their account has been seen connecting. There's deliberately no separate login or password for this panel: it recognizes the guest automatically for as long as they're genuinely logged into your WiFi through Captive Login, and disappears the moment they log out of WiFi — it was never designed as a standing account portal a guest could reach independently of an actual active WiFi session, precisely so a device that's logged out can't be used to keep viewing that guest's account details.
From the device list, a guest can sign out one specific device remotely — immediately revoking that device's own network access — useful if a device was lost, left logged in somewhere, or a login was shared further than intended. Signing out a device here is separate from that guest's own current device logging out of WiFi entirely (see Home).
Marketing Page
A separate pitch page (business.html), this one aimed at local businesses who might want to advertise on your captive rather than at guests joining your WiFi — reachable at your live address with /business on the end. It lays out your ad packages and pricing, how the ad-watch flow actually works for the businesses buying into it, and an inquiry form; submissions email straight to your own support address (the one configured under Email settings), not a shared ISN inbox. You control everything here through your branding settings the same way you do the guest-facing pages — logo, colors, and brand name all carry through.
Status Page
Your own service-health page (status.html), at /status on your live address — not to be confused with ISN's own platform status page, which reports on the infrastructure every tenant runs on, not any one tenant's own router or portal uptime specifically. This page reports on your location: whether your router and portal are actually reachable right now, and any maintenance windows or incidents you or ISN support have logged against your account specifically. Worth linking to from your own support channels if guests or your own staff ever ask "is the WiFi down for everyone, or just me?"
Captive Dashboard
Not the dashboard you're reading documentation for right now — this is the captive's own separate dashboard (business-dashboard.html), gated behind its own login, for whoever actually manages your ad campaigns day to day (an Admin or Ads/Marketing Manager team role, per Team members). It opens on a live analytics view — filterable by time range, granularity, and campaign — with active-campaign stat tiles, a top-campaigns chart, and a full results table, plus its own settings area. Reach it from Overview → Post ads & more in this dashboard, which signs you straight in with the same email and password, no second login to remember. A team member invited here as IT Department or Full Admin (per Team members) gets genuinely full control once inside — every settings area on this dashboard (business profile, banking details shown for advertiser payment, notifications, integrations/webhooks, security including its own two-factor authentication and active-session sign-out, and the Business Accounts screen below), not a cut-down or read-only subset. It isn't a second, weaker admin tier — it's the same authority your ISN Dashboard invite granted, carried through automatically.
Proof-of-play reports. Every campaign card under My Campaigns has a Proof of play button. Pick a date range and download a branded PDF or a CSV. The report shows how many times the ad played, how many different people saw it, how many watched to the end, skipped or clicked, and a breakdown by location (router name, area, and route or router group), by day, and by hour in South African time. It's what an advertiser or the agency that sold the slot hands its client as proof the campaign ran, for example a taxi-rank or on-route ad buy. It counts viewers but never lists who they were, so nothing in it is personal information. A report covers up to 400 days at a time. An advertiser can only pull reports for its own campaigns, while the captive's own admin can pull one for any campaign on its captive.
Why it's worth adding local businesses here, not just running your own campaigns: an Admin or IT team member can click Add Business to create a real, independent login for a local advertiser — a nearby shop, restaurant, or brand that wants to reach your guests — with just their business name and a login email (contact person, phone, and website are optional). That business gets its own invite email and password, no card or payment details needed to create the account, and logs into this exact same dashboard from then on to build and pay for its own campaigns and, where you've assigned them one, see the results of its own survey questions — without ever seeing your other data, your other advertisers, or your account settings. For you, it turns foot traffic you already have into an income stream you don't have to run yourself: you set the ad price and minimum spend once (Ad pricing), the business builds and funds its own campaign, and your revenue and Post ads & more views update as it delivers — all while keeping 100% of what that business pays you, since ISN is never a party to that arrangement at all (see My revenue).
Captive Dashboard redesign (September 2026)
The Captive Dashboard above (business-dashboard.html) went through a full visual and workflow redesign — same login, same data, same permissions, nothing about how any feature behaves changed. The old horizontal tab bar was replaced with a collapsible icon sidebar coloured in that captive's own brand colour, plus a frosted header showing which tab you're on. The Data tab's Live/Users/Businesses/Transactions/Routers sections used to sit empty until someone clicked Refresh — they now load automatically the moment the tab opens, and Live keeps itself updated every 15 seconds on its own. The last tab (and sub-tab) a user had open is now remembered across a page refresh instead of always resetting to Dashboard. Every table, pop-up dialog, and confirmation prompt across the dashboard was brought onto one consistent flat design in place of a mix of older solid-colour banners, and the phone layout was rebuilt (logo/name/menu header, icon-based hamburger drawer, tap-to-scroll on rows that scroll sideways). The full breakdown, written for the person actually using it day to day, is in that captive's own Help Centre — its live address with /help#whats-new on the end.
Still stuck on something?
This page is the full reference — for quick answers to the questions we hear most, see the Help Center. For anything neither page covers, email info@isnfreewifi.co.za with your tenant slug, domain, and router model so support can confirm what still needs attention before replying.
