From 4211f16d2cd57df73754ffcfab1b4f2a39ed8079 Mon Sep 17 00:00:00 2001 From: sarayourfriend <24264157+sarayourfriend@users.noreply.github.com> Date: Wed, 5 Apr 2023 02:10:47 +1000 Subject: [PATCH] Add more docs for Plausible and auto-initialise custom event names (#1122) * Add more docs for Plausible and auto-initialise custom event names * Update existing docs * Add caveat that it is not necessary to run Plausible if not working on custom events * Fix ToC --- documentation/guides/frontend/analytics.md | 129 ++++++++++++++++-- .../guides/frontend/goal-conversions.png | Bin 0 -> 23996 bytes documentation/guides/frontend/index.md | 1 + frontend/bin/get-custom-event-names.js | 33 +++++ setup_plausible.sh | 25 +++- 5 files changed, 175 insertions(+), 13 deletions(-) create mode 100644 documentation/guides/frontend/goal-conversions.png create mode 100644 frontend/bin/get-custom-event-names.js diff --git a/documentation/guides/frontend/analytics.md b/documentation/guides/frontend/analytics.md index 93e37a3427d..1efc7ed2bb7 100644 --- a/documentation/guides/frontend/analytics.md +++ b/documentation/guides/frontend/analytics.md @@ -1,23 +1,130 @@ # Analytics -Analytics on the frontend requires the Plausible setup to be up and running. +Openverse uses Plausible for analytics. This document describes how to set up +and use the Openverse Plausible integration. It is not necessary to set up +Plausible for general frontend development unless specifically working on custom +events. -## Starting up +Running Plausible locally requires Docker and docker-compose. -Bring up the Docker services needed by the frontend. This includes Plausible and -the PostgreSQL and Clickhouse databases it needs. +## Plausible set up and first run -```console +Use the following `just` recipes to set Plausible up locally: + +```sh +# Runs the portion of the docker-compose stack that includes Plausible $ just frontend/up + +# Sets up Plausible with a default user and the localhost testing site +# Only necessary the first time you run Plausible locally, when adding +# new custom events, or any time after you run `just down -v` +$ just frontend/init ``` -The `frontend/up` recipe orchestrates the following services: `plausible_ch`, -`plasible_db` and `plausible`. +If you have already run `just up` and `just init` at the root of the repository, +then Plausible is already set up and running the commands above is not +necessary. + +> **Note** +> +> `just frontend/up` may take some time on first run as it will need to download +> various docker images required for the Plausible stack. + +## Access Plausible + +Plausible is accessible at . The default localhost +username and password are: + +- Username: `deploy@example.com` +- Password: `deploy` + +Our setup script will have already added the "localhost" site used for testing +the Plausible integration on a locally running Openverse frontend. Refer to +[the frontend quickstart documentation](./quickstart.md) for instructions to set +up the Openverse frontend locally. + +## Custom events + +Plausible supports custom events via its "goals" feature. +[Plausible's documentation for this feature can be found here](https://plausible.io/docs/custom-event-goals). + +Sending custom events to Plausible is done by calling the `sendCustomEvents` +function. For this function to accept a custom event name, you must update the +`Events` type in `frontend/src/types/analyticts.ts` to include the new event +name and any payload elements unique to the event. + +Custom events must be added to Plausible for it to record them. You may do this +one of two ways: + +- Automatically: + 1. Run `just frontend/init`, which automatically extracts the events name + from the `Events` type +- Manually: + 1. Visit and click the "+ Add + goal" button + 2. Select the "custom event" trigger and add the custom event name in the + text box + 3. Click "add goal" to save the new custom event + +**If you are testing custom events added by others, you must also follow this +process for them to appear in your local environment. `just frontend/init` will +be the simplest way to do so in those cases, provided the change request +includes the necessary changes to the `Events` type.** + +After adding the custom event, upon receiving at least one instance of the +event, Plausible will display the event under the "Goal Conversions" section on +the stats page. It will look like this: + +![Plausible "Goal Conversions" example at bottom of site stats page](./goal-conversions.png) + +If you are adding a new custom event that includes unique payload elements, you +can click the custom event name in the "Goal Conversions" section to reveal the +payload elements and confirm that your payload items appear as expected. + +### Sending + +To send a custom event from the frontend, use the `sendCustomEvents` function +generated by the `useAnalytics` composable. For example: + +```ts +import { useAnalytics } from "~/composables/use-analytics" + +const { sendCustomEvent } = useAnalytics() +const handleClick = () => { + sendCustomEvent("COOL_EVENT_NAME", { + mediaType: props.mediaType, + }) +} +``` + +**You must set up the custom event following the instructions in the previous +section before this will do anything.** + +### Default payload -Now you should be able to access the following endpoints: +`sendCustomEvent` will automatically include the following payload elements: -- the Plausible UI on [http://localhost:50288](http://localhost:50288) +- `width`: The width of the screen in pixels at the time of the event +- `height`: The height of the screen in pixels at the time of the event +- `timestamp`: ISO formatted UTC timestamp of the time the event was sent +- `language`: The language the site was in when the event was sent +- `breakpoint`: One of the Openverse breakpoint values, for determining broad + page layout for a given event +- `ua`: The full user agent string +- `os`: The operating system of the user, extracted from the user agent string +- `platform`: The platform of the user, extracted from the user agent string +- `browser`: The name of the browser vendor, extracted from the user agent + string +- `version`: The browser version, extracted from the user agent string +- `origin`: The origin of the custom event, in production this will always be + `openverse.org` or `production.openverse.org` +- `pathname`: The path the user was on when the event was triggered +- `referrer`: The URL of the page that referred the user to the current page, if + any -## Shutting down +While these are included by default, any of them may not be present for a given +event instance if the information was not available at the time. For example, +referrer is not available if the page is visited directly. -Refer to the [common instructions](../quickstart.md#shutting-down). +Payload props unique to individual events may not use the same name as any of +the props listed above or they will overwrite the default props. diff --git a/documentation/guides/frontend/goal-conversions.png b/documentation/guides/frontend/goal-conversions.png new file mode 100644 index 0000000000000000000000000000000000000000..947b18d5703c75878be4162204e7f8c6b226e21a GIT binary patch literal 23996 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 a=T|ix{Ua-ZUv+-BP?lGhE0uZk@qYj>QPST4 literal 0 HcmV?d00001 diff --git a/documentation/guides/frontend/index.md b/documentation/guides/frontend/index.md index 80e89ab1419..b1a7e0e10ea 100644 --- a/documentation/guides/frontend/index.md +++ b/documentation/guides/frontend/index.md @@ -5,4 +5,5 @@ quickstart test +analytics ``` diff --git a/frontend/bin/get-custom-event-names.js b/frontend/bin/get-custom-event-names.js new file mode 100644 index 00000000000..afdbb277ef2 --- /dev/null +++ b/frontend/bin/get-custom-event-names.js @@ -0,0 +1,33 @@ +/** + * Extract custom event names from the `Events` type in `frontend/src/types/analytics.ts` + * This script is used by `setup_plausible.sh` to automatically provision + * existing custom events. + */ +const fs = require("fs") +const path = require("path") + +const ts = require("typescript") + +const analyticsTypesModule = path.resolve( + __dirname, + "..", + "src", + "types", + "analytics.ts" +) + +function main() { + const sourceFile = ts.createSourceFile( + analyticsTypesModule, + fs.readFileSync(analyticsTypesModule, "utf-8") + ) + + const eventsType = sourceFile.statements.find( + (s) => s.name.escapedText === "Events" + ) + const eventNames = eventsType.type.members.map((m) => m.name.escapedText) + + console.log(eventNames.join(" ")) +} + +main() diff --git a/setup_plausible.sh b/setup_plausible.sh index 8758bad6225..55f92cc2ae6 100755 --- a/setup_plausible.sh +++ b/setup_plausible.sh @@ -19,13 +19,16 @@ docker-compose exec -T "$PLAUSIBLE_DB_SERVICE_NAME" /bin/bash -c "psql -U deploy ON CONFLICT (id) DO NOTHING EOF" +authorization_header="Authorization: Bearer aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +local_plausible="http://localhost:50288" + # Create site using API key RES=$(curl \ -X POST \ - -H "Authorization: Bearer aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ + -H "$authorization_header" \ -F 'domain="localhost"' \ -F 'timezone="UTC"' \ - http://localhost:50288/api/v1/sites) + "$local_plausible/api/v1/sites") if [[ "$RES" == *"\"error\":\"domain This domain has already been taken"* ]]; then echo "Domain already exists." @@ -35,3 +38,21 @@ else echo "Error: $RES" exit 1 fi + +# Setup custom events +custom_events=$(node ./frontend/bin/get-custom-event-names.js) + +echo "Verifying custom events:" + +for eventName in $custom_events; +do + echo "$eventName" + curl \ + -X PUT \ + -s --output /dev/null \ + -H "$authorization_header" \ + -F 'site_id=localhost' \ + -F 'goal_type=event' \ + -F "event_name=$eventName" \ + "$local_plausible/api/v1/sites/goals" +done