Developer Guide

Cookies and visitor privacy

Every cookie a Cendia site can set, what each is for, and how a visitor opts out of tracking.

Under GDPR and the ePrivacy rules, a site has to tell visitors which cookies it sets and why. It also has to let them refuse the ones that are not strictly necessary. Cendia supplies the mechanism. The site supplies the question: where the choice appears (a banner, a privacy page, a footer link) and how it reads is a design decision, just like a language switcher.

This page is the list to build that notice from.

Cookies Cendia sets for visitors

Cookie Set when Lifetime Purpose Necessary?
cms_Visitor Visitor tracking is on 1 year, renewed on each visit A random id for this browser. Page views are recorded against it for the visit-history audience criteria. No: personalisation
cms_Session Visitor tracking is on 30 minutes, renewed on each request A random id for this visit. A visit ends after 30 minutes with no page view. Used by Time on Site, Number of Visits and the Forms criterion's "Session" option. No: personalisation
cms_TrackingOptOut The visitor opts out 1 year Remembers the opt-out. Yes: it is the refusal
mcform-sent-{form id} A form that allows only one submission is sent 1 year Stops the same browser sending that form twice. Yes: requested by the visitor's own action
.AspNetCore.Antiforgery.* A page renders a form Browser session Protects form posts from cross-site forgery. Yes: security
.AspNetCore.Mvc.CookieTempDataProvider A form post redirects back Until read Carries a form's errors or thank-you message across the redirect. Yes

Visitor tracking is off by default. With Cendia:EnableVisitorTracking unset, neither cms_Visitor nor cms_Session is ever written.

Cookies for people signed in to the CMS

These reach only authors and administrators, never an anonymous visitor.

Cookie Purpose
.AspNetCore.Identity.Application The CMS login.
.AspNetCore.Antiforgery.* Form protection in the editor.

Cookies your site sets

The starter code uses cookies of its own. They belong to your site, so list them if you keep them:

Cookie Purpose Necessary?
site.theme The visitor's light or dark choice. Yes: a preference they set
site.lang The visitor's language choice (Arena's switcher). Yes: a preference they set

What visitor tracking records

With tracking on, each rendered page view writes one row to cms_Collection_VisitorActivity:

  • the cms_Visitor and cms_Session ids
  • the path viewed, and its first segment
  • the language it was served in
  • the time
  • the IP address, which is personal data under GDPR. It is stored so that Number of Visits can count visits per address.

The JSON Delivery API, previews and the CMS editor are never recorded.

The Geographic Location criterion looks a visitor's address up in a database on your own server when a page is requested. It sets no cookie, stores nothing, and sends the address nowhere. See Geographic location.

Rows are deleted once they are older than Cendia:VisitorActivityRetentionDays, 90 by default. The Visitor Activity Retention scheduled job runs that sweep every hour.

{
  "Cendia": {
    "EnableVisitorTracking": true,
    "VisitorActivityRetentionDays": 90
  }
}

Letting visitors opt out

Cendia.AspNetCore.Audiences.VisitorTrackingConsent holds the building blocks:

using Cendia.AspNetCore.Audiences;

http.OptOutOfVisitorTracking();   // sets cms_TrackingOptOut, removes cms_Visitor and cms_Session
http.OptInToVisitorTracking();    // removes the opt-out; tracking resumes under new ids
http.IsVisitorTrackingOptedOut(); // for showing the current choice

After opting out:

  • No tracking cookie is set.
  • No page view is recorded.
  • Form submissions carry no visit id.

Every audience criterion that depends on tracking simply does not match for that visitor: Number of Visits, Time on Site, Visited Page (history), Visited Category, and Forms by session. Nothing errors, and the page renders exactly as it would for anyone outside the audience.

The development server (Cendia.Server) shows one way to offer the choice. Its footer carries a Personalisation: on / off link, mapped in TrackingPreference.cs:

app.MapGet("/set-tracking", (HttpContext http, string choice, string? returnUrl) =>
{
    if (choice == "off") http.OptOutOfVisitorTracking();
    else if (choice == "on") http.OptInToVisitorTracking();
    return Results.Redirect(SafeReturnUrl.Or(returnUrl));
});

A consent banner that asks before tracking starts works the same way. Opt the visitor out until they agree, then opt them in.

Signed-in visitors

The Forms criterion's "Logged in" option, and a form set to accept only signed-in visitors, need a sign-in for the site's visitors. The CMS login does not count. Cendia ships none. Your site registers one by implementing IVisitorIdentity:

public sealed class MyVisitorIdentity : IVisitorIdentity
{
    public AudienceVisitor? Current(HttpContext http) =>
        /* read your own sign-in: its user id, email and roles */;
}

builder.Services.AddScoped<IVisitorIdentity, MyVisitorIdentity>();

The development server's SiteIdentity.cs is a complete example built on ASP.NET Identity. It has its own user table and its own site.auth cookie, kept apart from the CMS login.