Skip to main content
20% off 3 months · code LAUNCH20 · until 31 October

Check your website traffic in Windsurf

Check your traffic without leaving the editor. With the Nordva Launch MCP server connected, the agent that just shipped a landing page can tell you how many people came, where from, which pages they read and how many reached the signup, and compare it with the week before.

Windsurf (now Devin Desktop) reads MCP servers from one file in your home directory, shared by every project. Remote servers take a serverUrl and optional headers.

Setup

You need a secret key (nv_live_…) from Dashboard → API keys.

01Add the server to mcp_config.json

~/.codeium/windsurf/mcp_config.json

{
  "mcpServers": {
    "nordva": {
      "serverUrl": "https://mcp.nordva.dev",
      "headers": {
        "Authorization": "Bearer nv_live_..."
      }
    }
  }
}

The field is serverUrl, not url. The file is outside your repositories, so the key can sit in it; Windsurf also replaces ${env:NAME} with an environment variable if you would rather keep it out. npx nordva init writes this file for you.

02Check the connection

In Cascade, open the MCP servers settings and refresh. nordva should be listed with its tools. Ask Cascade to run setup_check.

Then ask Windsurf

  • How many people visited this week, and is that up on last week?
  • Where did yesterday's visits come from?
  • Is anyone on the site right now?
  • Set up analytics on this site and add a goal to the signup button.
  • Where do people drop off between the home page and the signup?

For “How was traffic this week compared with last week?” Windsurf calls get_analytics_summary with:

{
  "period_days": 7
}

Returned: Visits, page views, average time on page and goal completions for the last 7 days, with the same numbers for the 7 days before, so the agent can say up or down without a second call.

Web analytics tools and arguments

get_analytics_summary

Read-only

Web analytics: the headline numbers

period_daysoptionalnumber, 1–1,825Days back from now. Default 7. Free reads up to 30, Indie 365, Builder 730. Past 90 days, older days come from daily totals (from_rollups: true): visitors are then each day's visitors added up, breakdowns end in an "(other)" row, and filters are refused.
filtersoptionalobjectShow only matching traffic, e.g. {"country":"NO"} or {"channel":"social"} or {"path":"/pricing"}. Values as they appear in get_analytics_breakdown.
exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

get_analytics_timeseries

Read-only

Web analytics: visits per day or hour

period_daysoptionalnumber, 1–1,825Days back from now. Default 7. Free reads up to 30, Indie 365, Builder 730. Past 90 days, older days come from daily totals (from_rollups: true): visitors are then each day's visitors added up, breakdowns end in an "(other)" row, and filters are refused.
bucketoptional"day" | "hour"
filtersoptionalobjectShow only matching traffic, e.g. {"country":"NO"} or {"channel":"social"} or {"path":"/pricing"}. Values as they appear in get_analytics_breakdown.
exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

get_analytics_breakdown

Read-only

Web analytics: by source, page, place or device

dimensionrequired"channel" | "referrer" | "utm_source" | "utm_medium" | "utm_campaign" | "path" | "country" | "city" | "device" | "browser" | "os" | "event"
period_daysoptionalnumber, 1–1,825Days back from now. Default 7. Free reads up to 30, Indie 365, Builder 730. Past 90 days, older days come from daily totals (from_rollups: true): visitors are then each day's visitors added up, breakdowns end in an "(other)" row, and filters are refused.
limitoptionalnumber, 1–100
filtersoptionalobjectShow only matching traffic, e.g. {"country":"NO"} or {"channel":"social"} or {"path":"/pricing"}. Values as they appear in get_analytics_breakdown.
exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

get_live_visitors

Read-only

Web analytics: right now

exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

list_visitors

Read-only

Web analytics: everyone who came, one row per visitor

period_daysoptionalnumber, 1–90Days back from now, up to 90 (raw events are kept 90 days). Free reads up to 30.
limitoptionalnumber, 1–200Default 50.
exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

get_visitor

Read-onlyBuilder

Web analytics: one visitor's history

visitor_idrequiredstring, max 40
period_daysoptionalnumber, 1–90Days back from now, up to 90 (raw events are kept 90 days). Free reads up to 30.

get_analytics_map

Read-only

Web analytics: where visits came from, as map points

period_daysoptionalnumber, 1–1,825Days back from now. Default 7. Free reads up to 30, Indie 365, Builder 730. Past 90 days, older days come from daily totals (from_rollups: true): visitors are then each day's visitors added up, breakdowns end in an "(other)" row, and filters are refused.
filtersoptionalobjectShow only matching traffic, e.g. {"country":"NO"} or {"channel":"social"} or {"path":"/pricing"}. Values as they appear in get_analytics_breakdown.
exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

get_analytics_status

Read-only

Web analytics: is the script sending?

No arguments.

get_analytics_usage

Read-only

Web analytics: events this month against the plan

No arguments.

get_analytics_settings

Read-only

Web analytics: the snippet and the site's domains

No arguments.

update_analytics_settings

Web analytics: set the site's domains, tracking mode, or turn collection on/off

domainsoptionalarray
enabledoptionalboolean
modeoptional"auto" | "consent" | "cookies" | "cookieless"Tracking mode. Only when the developer asks for a change.
signup_goaloptionalstringThe goal that counts as a signup; null for the recognised names.
signin_goaloptionalstringThe goal that counts as a sign-in; null for the recognised names.
excluded_countriesoptionalarrayCountries every read leaves out, e.g. ["NO","CH"]; [] for none. Only when the developer asks.

export_analytics

Read-only

Web analytics: take the data out as CSV or JSON

datasetoptional"daily" | "visitors" | "goals" | "channel" | "referrer" | "utm_source" | "utm_medium" | "utm_campaign" | "path" | "country" | "city" | "device" | "browser" | "os"
formatoptional"csv" | "json"
period_daysoptionalnumber, 1–3,650
exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

identify_visitor

Web analytics: link a visitor to a user

visitor_idoptionalstring, max 40The nv_vid cookie's value before the dot. Leave out when there is none.
user_idoptionalstring, max 128
emailoptionalstring, max 254
sourceoptionalstring, max 64Where the person came in, e.g. "ios-app". Lowercased to a tag.
detailsoptionalobjectName to value for the person's contact; null removes. Reuse names from list_contact_fields.
consentsoptionalobjectPurpose to true (granted) or false (withdrawn), only as the person gave it.

list_funnels

Read-only

Web analytics: the project's funnels

No arguments.

create_funnel

Web analytics: create a funnel

namerequiredstring, max 80
stepsrequiredarray

get_funnel_report

Read-only

Web analytics: where visitors drop off

funnel_idrequiredstring, max 64
period_daysoptionalnumber, 1–90Days back from now, up to 90 (raw events are kept 90 days). Free reads up to 30.
exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

delete_funnel

Confirms first

Web analytics: delete a funnel

funnel_idrequiredstring, max 64

get_goals

Read-only

Web analytics: goals and how many reach them

period_daysoptionalnumber, 1–1,825Days back from now. Default 7. Free reads up to 30, Indie 365, Builder 730. Past 90 days, older days come from daily totals (from_rollups: true): visitors are then each day's visitors added up, breakdowns end in an "(other)" row, and filters are refused.
limitoptionalnumber, 1–50
exclude_countryoptionalarrayTwo-letter country codes to leave out of this answer only, e.g. ["NO","CH"]. Omit to use the project's saved list; [] counts every country. To change the saved list use update_analytics_settings.

create_analytics_proxy_key

Web analytics: key for serving the script from your own domain

No arguments.

delete_analytics_proxy_key

Confirms first

Web analytics: remove the proxy key

No arguments.

Behaviour worth knowing

  • The agent installs the script itself: get_analytics_settings returns the one-line snippet and the site's domains, and the tool description tells the agent to put it in the shared layout so every page has it.
  • Visitors are only reported as a number when the tracking mode allows a visitor id; otherwise the agent speaks of visits, as the tool description tells it to.
  • Free reads up to 30 days back; paid plans up to 90 for now. One visitor's history (get_visitor) is on Builder.
  • No IP address is stored, and places are city-level with map points rounded to about 11 km.
  • The file is shared by all your projects, so it points at one Launch project at a time. Running npx nordva init in another project points it there.