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 00000000000..947b18d5703 Binary files /dev/null and b/documentation/guides/frontend/goal-conversions.png differ 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