Skip to content
Merged
80 changes: 80 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Contributing to Web Analytics

Thanks for your interest in improving Web Analytics for Umbraco. This guide covers the repository layout, how to set up a local development environment, and how to get a change merged. For how released package versions reach NuGet, see [docs/releasing.md](docs/releasing.md).

## Repository layout

This repository is a pnpm and .NET workspace. The most relevant folders:

| Path | What it is |
| --- | --- |
| `src/TheBuilder.WebAnalytics/` | The NuGet package: Umbraco API controllers, provider clients, services, and the packaging targets. |
| `src/TheBuilder.WebAnalytics/Client/` | The backoffice frontend (TypeScript, Lit, Vite). Built assets are emitted to `wwwroot/App_Plugins/`. |
| `samples/TheBuilder.WebAnalytics.Example/` | A runnable Umbraco site that references the package for local development. |
| `tests/TheBuilder.WebAnalytics.Tests/` | The .NET (xUnit) test project. Frontend tests (Vitest) live beside the client source. |
| `apps/docs/` | The documentation site (Blume) published to <https://umbraco-web-analytics.vercel.app/>. |
| `docs/releasing.md` | How package versions are published to NuGet. |

## Prerequisites

- [.NET SDK 10.0](https://dotnet.microsoft.com/download): builds the package, sample, and tests.
- [Node.js 24](https://nodejs.org/): builds the backoffice client and the docs site.
- [pnpm](https://pnpm.io/) via [Corepack](https://nodejs.org/api/corepack.html). Run `corepack enable` once; the pinned pnpm version is resolved automatically from `package.json`.

Install the JavaScript dependencies from the repository root:

```sh
pnpm install
```

## Build the backoffice client

The backoffice UI is a separate frontend build. A plain `dotnet build` of the sample does **not** rebuild it; the client is only built automatically when the NuGet package is packed. During development, build (or watch) the client yourself so its assets land in `wwwroot/App_Plugins/`:

```sh
pnpm client:build # one-off build
pnpm client:watch # rebuild on change and refresh the running backoffice
```

## Run the sample site

The example project references the package directly, so it always uses your local source. With the client already built, run it from the repository root:

```sh
dotnet run --project samples/TheBuilder.WebAnalytics.Example
```

On first launch Umbraco installs unattended and creates a local SQLite database. In `Development` the sample enables mock connections (`WebAnalytics:EnableMockConnections`), so the Analytics section shows deterministic sample data without any Vercel or Plausible credential. For live data, configure a real provider credential and connection exactly as a consumer would (see the [Quickstart](https://umbraco-web-analytics.vercel.app/quickstart)).

For an efficient loop, run `pnpm client:watch` in one terminal and `dotnet run` in another.

## Run the tests and checks

```sh
pnpm test # frontend unit tests (Vitest)
pnpm client:check # frontend type-check
dotnet test tests/TheBuilder.WebAnalytics.Tests/TheBuilder.WebAnalytics.Tests.csproj # .NET tests
```

The .NET suite runs against Umbraco 17.1, the latest 17.x, and the latest 18.x in CI. Target a specific line locally by passing the version, for example `-p:UmbracoVersion=18.*`.

## Work on the documentation site

```sh
pnpm docs:dev # local preview with hot reload
pnpm docs:build # production build
pnpm docs:check # validate content and links
```

The `apps/docs/` content is Markdown/MDX; see the files under `apps/docs/docs/` for structure.

## Submitting a change

1. Create a branch for your change.
2. Keep pull requests focused, and update the relevant docs under `apps/docs/` when behaviour changes.
3. Run the frontend and .NET tests above so CI passes on the first try. The `Validate` workflow builds the client, runs both test suites across the supported Umbraco versions, and validates the NuGet package.
4. Open a pull request against `main` with a clear description of the change and its motivation.

## Releasing

Publishing packages to NuGet is release-driven and documented separately in [docs/releasing.md](docs/releasing.md). Published release notes appear in the [documentation changelog](https://umbraco-web-analytics.vercel.app/changelog/).
91 changes: 82 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ Bring Vercel Web Analytics and Plausible reports into the Umbraco backoffice. Ed

Web Analytics reads analytics already collected by the configured provider. It does **not** install, replace, or configure tracking on your public website.

## Documentation

Read the [Web Analytics documentation](https://umbraco-web-analytics.vercel.app/) for installation, provider setup, document analytics, configuration reference, troubleshooting, and the release changelog.

## Install

Web Analytics supports Umbraco CMS 17.1 through 18.x. Add it to the Umbraco web project:
Expand All @@ -22,17 +18,94 @@ Web Analytics supports Umbraco CMS 17.1 through 18.x. Add it to the Umbraco web
dotnet add package TheBuilder.WebAnalytics
```

The package registers its services and backoffice extensions automatically. Configure a Vercel or Plausible credential in server-side secret configuration, then add and test a connection at **Settings → Web Analytics**.
Your public site must already collect analytics with Vercel or Plausible; this package reads that data and does not add tracking of its own.

The package registers its services and backoffice extensions automatically. Then:

1. Configure a provider credential in server-side secret configuration (see below).
2. Restart the Umbraco application so it reads the credential.
3. As an administrator, open **Settings → Web Analytics**, add a connection, and select **Test connection**.
4. Open the **Analytics** section to verify that reports load.

To let non-admin editors see reporting, grant the **Analytics** section to their user group; the automatic administrator grant runs only once.

## Providers

| Provider | Identifier | Credential |
| --- | --- | --- |
| [Vercel Web Analytics](https://vercel.com/docs/analytics) | Project ID (`prj_...`) and optional team | Scoped access token |
| [Plausible](https://plausible.io/docs/stats-api) | Site ID, normally the registered domain | Stats API key |
| [Vercel Web Analytics](https://umbraco-web-analytics.vercel.app/providers/vercel) | Project ID (`prj_...`) and optional team | Scoped access token |
| [Plausible](https://umbraco-web-analytics.vercel.app/providers/plausible) | Site ID, normally the registered domain | Stats API key |

Plausible Cloud's Stats API requires a Business plan. Self-hosted Plausible is supported when its instance exposes the v2 Stats API query endpoint.

## Contributing and releases
## Configure a credential

Provider credentials are always read from **server-side configuration** and are never stored in Umbraco or exposed to the browser. Keep them out of `appsettings.json` and source control. Use environment variables, [.NET user secrets](https://learn.microsoft.com/aspnet/core/security/app-secrets), or your hosting platform's secret store. Restart every application instance after adding or rotating a credential.

The configuration keys use the standard .NET double-underscore (`__`) delimiter for environment variables, or `:` for user secrets and JSON.

### Vercel

1. Create a [Vercel access token](https://vercel.com/kb/guide/how-do-i-use-a-vercel-api-access-token) scoped to the account or team that owns the project.
2. Provide it as `WebAnalytics__Providers__Vercel__AccessToken`.
3. Note the project ID (`prj_...`), and the team ID (`team_...`) or slug for a team-owned project, to enter in Settings.

```sh
dotnet user-secrets set "WebAnalytics:Providers:Vercel:AccessToken" "your_token" --project path/to/Your.Umbraco.Web.csproj
```

### Plausible

1. Create a [Plausible Stats API key](https://plausible.io/docs/stats-api) for the site you want to connect.
2. Provide it as `WebAnalytics__Providers__Plausible__AccessToken`.
3. Note the Site ID (normally the registered domain) to enter in Settings.
4. For a self-hosted instance, set `WebAnalytics__Providers__Plausible__BaseUrl` to its public base URL (it must expose `/api/v2/query`). Cloud users keep the default `https://plausible.io/`.

```sh
dotnet user-secrets set "WebAnalytics:Providers:Plausible:AccessToken" "your_stats_api_key" --project path/to/Your.Umbraco.Web.csproj
dotnet user-secrets set "WebAnalytics:Providers:Plausible:BaseUrl" "https://analytics.example.com/" --project path/to/Your.Umbraco.Web.csproj
```

### Per-connection credential override (optional)

When one connection needs a different credential from the shared provider token, set a connection-specific override keyed by the connection GUID. The Settings screen shows the exact key. An override takes precedence over the shared provider credential.

```text
WebAnalytics__ConnectionAccessTokens__{connection-guid}
```

## Configuration

The Settings screen (**Settings → Web Analytics**) is the normal way to manage connections. Configuration precedence works as follows:

- At startup the package reads the `WebAnalytics` section from server configuration.
- Until an administrator first saves Settings, those non-secret values are the active configuration.
- After the first save, non-secret connection settings are stored in Umbraco and become the source of truth.
- Provider **credentials always remain in server-side configuration**, regardless of saved settings.

Each application instance keeps its own in-memory report cache, so restart every instance after changing saved settings or credentials.

Besides the provider credentials above, these tunables live under the `WebAnalytics` section:

| Key | Default | Description |
| --- | --- | --- |
| `Enabled` | `true` | Enables the Analytics section and configured document workspace views. |
| `DefaultRangeDays` | `30` | Initial reporting range, in days. Valid values are 1 to 730. |
| `CacheDuration` | `00:05:00` | Per-instance in-memory cache duration. Valid from zero to one hour. |
| `Connections` | `[]` | Provider connection definitions. The first becomes the initial default. |
| `EnableMockConnections` | `false` | Development-only deterministic connection presets. Never enable in production. |

Connections are normally created through the Settings screen, but they can also be bootstrapped from configuration for deployment automation. The [configuration reference](https://umbraco-web-analytics.vercel.app/reference/configuration) documents every connection key and the full precedence rules.

## Documentation

The full documentation site covers everything above in more depth, plus the reporting UI and per-provider capabilities:

- [Quickstart](https://umbraco-web-analytics.vercel.app/quickstart): install, connect a provider, and verify the dashboard.
- [Understanding your reports](https://umbraco-web-analytics.vercel.app/guides/reports): what each metric, breakdown, and control means.
- [Document analytics](https://umbraco-web-analytics.vercel.app/guides/document-analytics): show page-level reports on mapped documents.
- [Configuration reference](https://umbraco-web-analytics.vercel.app/reference/configuration) and [troubleshooting](https://umbraco-web-analytics.vercel.app/reference/troubleshooting).

## Contributing

Development and NuGet publishing guidance is kept in [docs/releasing.md](docs/releasing.md). Published release notes are available in the [documentation changelog](https://umbraco-web-analytics.vercel.app/changelog/).
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for the repository layout, local development setup (building the backoffice client, running the sample site, and running the tests), and how to submit a pull request. NuGet publishing guidance is in [docs/releasing.md](docs/releasing.md), and published release notes are in the [documentation changelog](https://umbraco-web-analytics.vercel.app/changelog/).
2 changes: 0 additions & 2 deletions apps/docs/docs/guides/document-analytics.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ Global and document analytics are intentionally separate:

This means an editor can see analytics for a document they can browse without gaining access to global site reporting.

Document reports do not require global Analytics-section access.

## Troubleshoot a missing workspace

Check publication and route state first, then the nearest root mapping and document-type setting. If the workspace still does not appear, verify Content-section access and document browse permission. See [troubleshooting](/reference/troubleshooting) for the full symptom checklist.
2 changes: 1 addition & 1 deletion apps/docs/docs/guides/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ export default defineMeta({
title: "Guides",
icon: "book-open",
order: 2,
pages: ["document-analytics"],
pages: ["reports", "document-analytics"],
});
74 changes: 74 additions & 0 deletions apps/docs/docs/guides/reports.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
title: Understanding your reports
description: What each metric, breakdown, control, and drill-down in the Analytics dashboard means, and how date comparison and filtering work together.
---

The Analytics section presents one dashboard per connection. This page explains what every part of it shows so you can move from a headline number to the context behind it. It describes the reading experience; for setup see the [quickstart](/quickstart), and for page-level reports see [document analytics](/guides/document-analytics).

![The global Analytics dashboard in the Umbraco backoffice](../screenshots/analytics-overview.png)

## Dashboard controls

The header holds the two controls that shape every report below it.

| Control | What it does |
| --- | --- |
| **Analytics connection** | Switches between configured connections when more than one exists. Every metric, breakdown, and filter is scoped to the selected connection. |
| **Date range** | Choose a preset (Last 24 hours, Last 7 days, Last 30 days, Last 90 days, or Last 12 months) or set a custom range. The default range is 30 days and is configurable with `DefaultRangeDays`. |

The range you pick also sets how history is grouped: hourly for a single day, daily up to a month, weekly up to a quarter, and monthly beyond that.

## Metrics and history

Two headline metrics sit at the top of the dashboard:

- **Visitors**: the number of distinct people who visited in the selected range.
- **Page views**: the total number of pages those visitors loaded.

Each metric shows its total and, automatically, a comparison against the immediately preceding period of the same length. There is no separate toggle. The badge reads as a signed percentage such as `+12%`, with a fuller description like "12% more visitors than the previous 30 days". When the previous period has no data to compare against, the badge is omitted rather than shown as a misleading change.

Select a metric to plot it over time. The history chart uses the interval implied by the range, and the final segment is drawn as in-progress when the current period is not yet complete.

## Breakdowns

Breakdowns rank the dimensions that make up your traffic. Each card lists the top contributors with a proportional bar and the metric value; **View all** opens a searchable dialog with the complete, filterable list.

| Card | Shows |
| --- | --- |
| **Pages** | The most-visited request paths. (Hidden on a document report, which is already scoped to one page.) |
| **Acquisition** | Where traffic came from. A **Referrers** tab lists the sites and sources that sent visitors; when the connection supports UTM reporting, a **UTM** tab adds sub-tabs for **Source**, **Medium**, **Campaign**, **Term**, and **Content** from tagged marketing links. |
| **Countries** | Visitors grouped by country. |
| **Audience** | A tabbed card covering **Devices** and **Browsers**. |
| **Operating systems** | Visitors grouped by operating system. |

UTM reporting is capability- and plan-dependent, so the **UTM** tab appears only when the selected connection can report those dimensions. On a plan-limited connection, the card explains that "UTM reporting availability depends on your analytics plan and reporting window."

## Events

When the provider records custom events, the dashboard adds an **Events** panel listing each event and its total. Select an event and choose **View all events** to open the full, searchable list, then open an event to drill into its properties.

![Custom event details with a property drill-down](../screenshots/custom-event-details.png)

Event-property drill-downs let you break a single event down by a recorded property, for example which URLs an outbound-link event pointed to. For Plausible, configure the property names you want to explore under the connection's event-property settings; see the [Plausible reference](/providers/plausible#event-properties).

## Feature flags

For Vercel connections that report feature flags, a **Flags** panel lists each flag with its totals, and **View all flags** opens the complete list. Plausible does not expose feature flags, so the panel is hidden for Plausible connections rather than shown as an error.

![Audience, events, and feature-flag panels](../screenshots/audience-events-and-flags.png)

## Filtering and drill-downs

Any breakdown row can become a filter. Hover or keyboard-focus a row to reveal **Filter by this value**; applying it narrows every report on the dashboard to that value, for example only visitors from one country, or only one referrer.

Active filters appear as a **Filters** group beneath the header. Remove an individual filter from its chip, or choose **Clear all** to return to the unfiltered view. Filters, the selected date range, and the chosen breakdown tabs are reflected in the dashboard URL, so a filtered view can be bookmarked or shared.

![Active filters applied to the dashboard](../screenshots/analytics-filters.png)

:::note[Provider differences are expected]
The interface adapts to what each provider supports instead of showing errors. Vercel does not support applying an event or event-property filter to a global report or choosing the ordering metric for a breakdown; Plausible supports both but has no feature flags. A hidden panel means the provider does not offer that capability, not a failed connection. See the [Vercel](/providers/vercel#capabilities) and [Plausible](/providers/plausible#capabilities) references for the exact per-provider capabilities.
:::

## Reports on a document

The same metrics, history, and breakdowns appear in the Analytics workspace on a mapped document, automatically scoped to that document's published route. The document view adds an **Include child paths** toggle to report on either the single page or the whole section beneath it. See [document analytics](/guides/document-analytics) for mapping and permissions.
2 changes: 1 addition & 1 deletion apps/docs/docs/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Choose the reference for the analytics provider your site already has.

## What you get

- **Traffic reports.** Explore visitors, page views, trends, acquisition, audience, pages, routes, and campaigns.
- **Traffic reports.** Explore visitors, page views, trends, referrers, campaigns, countries, devices, and pages. [Understand what each report means](/guides/reports).
- **Document context.** Show analytics in mapped published document workspaces, scoped to the document's route.
- **Useful detail.** Use date comparisons, filters, and drill-downs to move from a headline number to useful context.
- **Multi-site support.** Add more than one connection to an Umbraco installation.
Expand Down
Loading