Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/analytics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,23 @@ entry that earned them rather than to a URL string.
> and an Analytics panel in the entry editor. Tested on EmDash 0.39 and 0.40.
> See "Not in this version".

The screenshots show demo data on a site made from EmDash's blog template.

## The dashboard widget

A **Traffic** card on the dashboard: visits and page views for the last
seven days against the week before, the five most viewed pages with the
entry they belong to, and when the numbers were last synced.

<img src="https://raw.githubusercontent.com/eisbachcode/emdash-plugins/main/packages/analytics/screenshots/widget.png" width="554" alt="The Traffic widget: visits and page views for the last 7 days with their change against the previous week, and the five most viewed pages with entry title, path and views">

## The Analytics page

**Plugins → Analytics** in the admin sidebar, or "Open analytics" on the
dashboard widget. Editors and admins see it.

<img src="https://raw.githubusercontent.com/eisbachcode/emdash-plugins/main/packages/analytics/screenshots/analytics-page.png" width="820" alt="The Analytics page over 30 days: visits and page views with their change, a daily chart, top entries with collection, path, views and visits, and tables of referrers and countries">

The page asks the provider live on every load, so it has numbers from the
first minute after setup; it does not wait for the sync. It only ever asks
for the days the provider still counts exactly (for Cloudflare, the last
Expand Down Expand Up @@ -55,9 +67,14 @@ views, so the right one can be copied into the settings.
The check only reads; values are entered in the plugin's settings form. It
makes one request to Cloudflare.

<img src="https://raw.githubusercontent.com/eisbachcode/emdash-plugins/main/packages/analytics/screenshots/setup-check.png" width="820" alt="The setup check with every row OK: data source, site URL, content index with 8 entries matched, scheduled sync and last sync">

## Analytics per entry

**Plugins → Analytics per entry**, or "Per entry" on the Analytics page.

<img src="https://raw.githubusercontent.com/eisbachcode/emdash-plugins/main/packages/analytics/screenshots/per-entry.png" width="820" alt="Analytics per entry: every published entry with its collection, path, page views over 7 and 30 days and publish date, most viewed first">

Every published entry with its page views over the last 7 and 30 days,
today included, by collection or across all of them. Click a column header
to sort; sorting ascending puts the entries nobody visited first, which
Expand All @@ -84,6 +101,8 @@ URL.

## The editor panel

<img src="https://raw.githubusercontent.com/eisbachcode/emdash-plugins/main/packages/analytics/screenshots/editor-panel.png" width="375" alt="The Analytics panel in the entry editor: page views over the last 7 and 30 days and the path they are counted at">

In the entry editor, the **Analytics** panel shows that entry's 7- and 30-day
page views and the path they are counted at, and on a translated entry
each language's numbers and their total. An entry that is not published
Expand All @@ -97,6 +116,7 @@ at a public URL says so instead.
| A Cloudflare account | with Web Analytics enabled for the site |
| An API token | permission **Account → Account Analytics → Read** |
| `EMDASH_ENCRYPTION_KEY` | set on the site, or the API token cannot be stored (`npx emdash secrets generate`) |
| URL patterns | each collection needs a **URL Pattern** (under Content Types), or no page can be matched to its entry. Sites made from EmDash's blog template start without them; the setup check says so |
| Scheduled tasks | the sync runs as a plugin cron task. On Cloudflare Workers that needs the Cron Trigger and `scheduled` handler from EmDash's Cloudflare deployment guide; on Node, EmDash runs them itself |

### The token scope, precisely
Expand Down
11 changes: 10 additions & 1 deletion packages/analytics/emdash-plugin.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@
// break. The manifest has no advisory "tested up to" field to express
// caution without blocking, so the tested range belongs in the README.
"release": {
"requires": { "env:emdash": ">=0.39.0" }
"requires": { "env:emdash": ">=0.39.0" },
"artifacts": {
"screenshots": [
{ "file": "screenshots/analytics-page.png", "lang": "en" },
{ "file": "screenshots/per-entry.png", "lang": "en" },
{ "file": "screenshots/widget.png", "lang": "en" },
{ "file": "screenshots/editor-panel.png", "lang": "en" },
{ "file": "screenshots/setup-check.png", "lang": "en" }
]
}
},
// Registry search indexes slug and description and has no keywords
// field, so every provider this plugin supports has to be named here.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/analytics/screenshots/editor-panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/analytics/screenshots/per-entry.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/analytics/screenshots/setup-check.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/analytics/screenshots/widget.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions packages/analytics/src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const en = {
noEntriesYet: "No entries yet",
noEntriesIndexing: "The content index is still being built. Entries appear as it progresses.",
noEntriesNoUrls:
"No published entry has a public URL. Check that the site URL is set in EmDash and that the collections have URL patterns.",
"No published entry has a public URL. Check that the site URL is set in EmDash and that each collection has a URL Pattern (under Content Types), then press Rebuild index on the per-entry page.",
noEntriesHere: "No published entries here.",
panelNoPage: "No page for this entry yet",
panelNoPageDetail: "Views appear once the entry is published at a public URL and the next sync has run.",
Expand Down Expand Up @@ -123,7 +123,7 @@ const en = {
hostsNone:
"Cloudflare reports this site tag under {reported}, but the plugin counts only {counted}. Change Hostnames to count in the plugin's settings.",
siteUrlMissing:
"EmDash has no site URL stored, so entries have no public address and page views cannot be matched to them. EmDash stores it (the emdash:site_url option) when the setup wizard runs on the live domain.",
"EmDash has no site URL, so entries have no public address and page views cannot be matched to them. EmDash stores it (the emdash:site_url option) when the setup wizard runs on the live domain; a server that was already running picks it up after a restart.",
needsSiteUrl: "Needs the site URL.",
indexMatched: { one: "{count} entry matched to its page.", other: "{count} entries matched to their pages." },
schedulerNotScheduled: "The sync is not scheduled yet. Opening the dashboard schedules it.",
Expand Down Expand Up @@ -254,7 +254,7 @@ const de: Record<MessageKey, Message> = {
noEntriesYet: "Noch keine Einträge",
noEntriesIndexing: "Der Inhaltsindex wird noch aufgebaut. Einträge erscheinen nach und nach.",
noEntriesNoUrls:
"Kein veröffentlichter Eintrag hat eine öffentliche URL. Prüfe, ob die URL der Webseite in EmDash eingetragen ist und die Kollektionen URL-Muster haben.",
"Kein veröffentlichter Eintrag hat eine öffentliche URL. Prüfe, ob die URL der Website in EmDash eingetragen ist und jede Kollektion ein URL-Muster hat (unter Inhaltstypen), und drücke dann „Index neu aufbauen“ auf der Seite pro Eintrag.",
noEntriesHere: "Hier gibt es keine veröffentlichten Einträge.",
panelNoPage: "Noch keine Seite für diesen Eintrag",
panelNoPageDetail:
Expand Down Expand Up @@ -310,7 +310,7 @@ const de: Record<MessageKey, Message> = {
hostsNone:
"Cloudflare meldet dieses Site-Tag unter {reported}, das Plugin zählt aber nur {counted}. Ändere Hostnames to count in den Einstellungen des Plugins.",
siteUrlMissing:
"EmDash hat keine Website-URL gespeichert, deshalb haben Einträge keine öffentliche Adresse und Seitenaufrufe lassen sich ihnen nicht zuordnen. EmDash speichert sie (die Option emdash:site_url), wenn der Einrichtungsassistent auf der Live-Domain läuft.",
"EmDash hat keine Website-URL, deshalb haben Einträge keine öffentliche Adresse und Seitenaufrufe lassen sich ihnen nicht zuordnen. EmDash speichert sie (die Option emdash:site_url), wenn der Einrichtungsassistent auf der Live-Domain läuft; ein Server, der da schon lief, übernimmt sie nach einem Neustart.",
needsSiteUrl: "Braucht die Website-URL.",
indexMatched: {
one: "{count} Eintrag ist seiner Seite zugeordnet.",
Expand Down
5 changes: 4 additions & 1 deletion packages/analytics/tests/setup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ describe("each failure, with the sentence that names its fix", () => {

it("a finished index that matched nothing although the URL is set", () => {
const facts = { ...healthy(), state: { ...healthy().state, indexed: 0 } };
expect(check(facts, "index")).toMatchObject({ status: "problem", detail: expect.stringMatching(/URL patterns/) });
expect(check(facts, "index")).toMatchObject({
status: "problem",
detail: expect.stringMatching(/URL Pattern \(under Content Types\), then press Rebuild index/),
});
});

it("a host without a scheduler", () => {
Expand Down
Loading