{"id":17245130,"url":"https://github.com/andrerfcsantos/go-plausible","last_synced_at":"2026-03-04T07:33:04.745Z","repository":{"id":57587221,"uuid":"372243560","full_name":"andrerfcsantos/go-plausible","owner":"andrerfcsantos","description":"Plausible API wrapper for Go","archived":false,"fork":false,"pushed_at":"2025-02-23T18:39:30.000Z","size":96,"stargazers_count":22,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-27T09:37:54.829Z","etag":null,"topics":["api-wrapper","go","golang","plausible-analytics"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrerfcsantos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-05-30T15:01:07.000Z","updated_at":"2025-09-09T09:10:19.000Z","dependencies_parsed_at":"2025-06-20T16:31:30.766Z","dependency_job_id":null,"html_url":"https://github.com/andrerfcsantos/go-plausible","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/andrerfcsantos/go-plausible","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrerfcsantos%2Fgo-plausible","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrerfcsantos%2Fgo-plausible/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrerfcsantos%2Fgo-plausible/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrerfcsantos%2Fgo-plausible/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrerfcsantos","download_url":"https://codeload.github.com/andrerfcsantos/go-plausible/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrerfcsantos%2Fgo-plausible/sbom","scorecard":{"id":193023,"data":{"date":"2025-08-11","repo":{"name":"github.com/andrerfcsantos/go-plausible","commit":"7550148d1b7edc2e6be3102bd1b9fa3385d9f3fa"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":2,"reason":"Found 4/15 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":5,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Warn: 'branch protection settings apply to administrators' is disabled on branch 'main'","Warn: 'stale review dismissal' is disabled on branch 'main'","Warn: required approving review count is 1 on branch 'main'","Warn: codeowners review is not required on branch 'main'","Warn: 'last push approval' is disabled on branch 'main'","Warn: no status checks found to merge onto branch 'main'","Info: PRs are required in order to make changes on branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0355 / GHSA-fx95-883v-4q4h"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T21:11:12.454Z","repository_id":57587221,"created_at":"2025-08-16T21:11:12.454Z","updated_at":"2025-08-16T21:11:12.454Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30075434,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T05:31:57.858Z","status":"ssl_error","status_checked_at":"2026-03-04T05:31:38.462Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-wrapper","go","golang","plausible-analytics"],"created_at":"2024-10-15T06:28:40.506Z","updated_at":"2026-03-04T07:33:04.715Z","avatar_url":"https://github.com/andrerfcsantos.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003ca name=\"top\"\u003e\u003c/a\u003e `go-plausible` - Go Wrapper for the Plausible API\r\n\r\n[![Go Reference](https://pkg.go.dev/badge/github.com/andrerfcsantos/go-plausible/plausible.svg)](https://pkg.go.dev/github.com/andrerfcsantos/go-plausible/plausible) [![Go Report Card](https://goreportcard.com/badge/github.com/andrerfcsantos/go-plausible)](https://goreportcard.com/report/github.com/andrerfcsantos/go-plausible)\r\n\r\nGo wrapper/client for the [Plausible](https://plausible.io/) API.\r\n\r\nIt currently supports the full API of Plausible, which includes:\r\n\r\n* [Stats API](https://plausible.io/docs/stats-api)\r\n* [Site Provisioning API](https://plausible.io/docs/sites-api)\r\n\r\n## Table of Contents\r\n\r\n* [Basic Usage](#basic-usage)\r\n\r\n* [Concepts](#concepts)\r\n    * [Time Periods](#time-periods)\r\n    * [Properties](#properties)\r\n    * [Filters](#filters)\r\n    * [Metrics](#metrics)\r\n    * [Time Intervals](#metrics)\r\n\r\n* [Queries (Stats API)](#queries)\r\n    * [Current Visitors](#currrent-visitors)\r\n    * [Aggregate Queries](#aggregate-queries)\r\n    * [Time series Queries](#timeseries-queries)\r\n    * [Breakdown Queries](#breakdown-queries)\r\n\r\n* [Site Provisioning API](#site-provisioning-api)\r\n    * [List sites](#provisioning-api-get-sites)\r\n    * [Get site](#provisioning-api-get-site)\r\n    * [Get/Create Shared Links](#provisioning-api-shared-links)\r\n    * [Create new sites](#provisioning-api-create-new-sites)\r\n\r\n* [Events API](#events-api)\r\n\r\n* [Tests](#tests)\r\n    * [Unit Tests](#unit-tests)\r\n    * [Integration Tests](#integration-tests)\r\n    * [Integration Tests with provisioning API](#integration-tests-provisioning)\r\n\r\n* [Bugs and Feedback](#bugs-feedback)\r\n* [Contributing](#contributing)\r\n* [License](#license)\r\n\r\n## \u003ca name=\"basic-usage\"\u003e\u003c/a\u003e Basic Usage\r\n\r\n```go\r\nimport \"github.com/andrerfcsantos/go-plausible/plausible\"\r\n```\r\n\r\nTo use this client, you'll need an API token, which you can get from the Plausible Dashboard.\r\n\r\nWith the API token, create a client and get a handler for one or more sites:\r\n\r\n```go\r\npackage main\r\n\r\nimport \"github.com/andrerfcsantos/go-plausible/plausible\"\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\t// Get an handler to perform queries for a given site\r\n\tmysite := client.Site(\"example.com\")\r\n\r\n\t// You can reuse the same client to get handlers for additional sites\r\n\tmyothersite := client.Site(\"otherexample.com\")\r\n}\r\n```\r\n\r\n## \u003ca name=\"concepts\"\u003e\u003c/a\u003e Concepts\r\n\r\nThere a few concepts that are useful to know before using this wrapper or the Plausible API.\r\n\r\n### \u003ca name=\"time-periods\"\u003e\u003c/a\u003e Time Periods\r\n\r\nWhen requesting aggregate information to the API, it's only possible to get data for a given period of time. For\r\ninstance,\r\n\"the last 7 days\", \"the last month\" or \"the current day\" are examples of time periods.\r\n\r\nAll time periods are relative to a date. When the date information is missing from a time period, the date is assumed to\r\nbe \"today\". It's also possible to specify a time period between two specific dates.\r\n\r\nTime periods are represented in this library by\r\nthe [TimePeriod](https://pkg.go.dev/github.com/andrerfcsantos/go-plausible/plausible#TimePeriod) type.\r\n\r\nUnless you want low-level access to the API, you don't need to create a `TimePeriod` directly, and you can just use the\r\nhelper functions to build a time period:\r\n\r\n```go\r\n// Get the period for the last 6 months from today\r\np := plausible.Last6Months()\r\n```\r\n\r\nTo associate a date to a time period, chain the result with `FromDate()` or\r\n`OfDate()`:\r\n\r\n```go\r\n// Get the period for the last 12 months from the 1st of January 2021\r\np := plausible.Last12Months().FromDate(plausible.Date{Day:1, Month: 1, Year: 2021})\r\n```\r\n\r\nTo make a custom period between 2 dates:\r\n\r\n```go\r\n// Get the period for the first 15 days of 2021\r\np := plausible.CustomPeriod(plausible.Date{Day:1, Month: 1, Year: 2021}, plausible.Date{Day:15, Month: 1, Year: 2021})\r\n```\r\n\r\nTo know more about time periods, see [Plausible Docs: Time Periods](https://plausible.io/docs/stats-api#time-periods)\r\n\r\n### \u003ca name=\"properties\"\u003e\u003c/a\u003e Properties\r\n\r\nEach pageview or custom event has some properties associated with it. These properties can be used when querying the API\r\nto filter the results.\r\n\r\nProperties are represented in this library by\r\nthe [Property](https://pkg.go.dev/github.com/andrerfcsantos/go-plausible/plausible#Property)\r\ntype. Properties have a name and value. The name of a property is represented by\r\nthe [PropertyName](https://pkg.go.dev/github.com/andrerfcsantos/go-plausible/plausible#PropertyName)\r\ntype. Typically, most users won't need to make custom property names and can just use the constant `PropertyName`\r\nvalues declared at the top-level of the package like `VisitOs` or `VisitBrowser`.\r\n\r\nTo make a custom `PropertyName`, the function `CustomPropertyName()` can be used:\r\n\r\n```go\r\npName := plausible.CustomPropertyName(\"myevent\")\r\n```\r\n\r\nObtaining custom property names via this method is needed when you have custom events and want to refer to those events\r\nas a property.\r\n\r\nTo easily make a custom property with a name and a value, you can use the `CustomProperty` function:\r\n\r\n```go\r\np := plausible.CustomProperty(\"myevent\", \"myeventvalue\")\r\n```\r\n\r\nTo know more about properties, see [Plausible Docs: Properties](https://plausible.io/docs/stats-api#properties)\r\n\r\n### \u003ca name=\"filters\"\u003e\u003c/a\u003e Filters\r\n\r\nFilters allow drilling down and segment the data to which the results refer to. All queries for data accept an optional\r\nfilter argument.\r\n\r\nIn this library, filters are represented by\r\nthe [Filter](https://pkg.go.dev/github.com/andrerfcsantos/go-plausible/plausible#Filter) type.\r\n\r\nA filter consists of a simple list of properties by which you want to filter. For instance, to create a filter that\r\nfilters all visits by their operating system, you can do:\r\n\r\n```go\r\nf := plausible.NewFilter().ByVisitOs(\"Windows\")\r\n```\r\n\r\nYou can add more properties to the filter by chaining calls:\r\n\r\n```go\r\nf := plausible.NewFilter().ByVisitOs(\"Windows\").ByVisitBrowser(\"Firefox\")\r\n```\r\n\r\nThis will filter the results based on the visits from Windows users that were using Firefox. So, a filter basically\r\nconsists of a logic AND of all its properties.\r\n\r\nYou can also instantiate a filter directly if you want a more low-level access to the API. For instance, this an\r\nalternative way to write the filter above:\r\n\r\n```go\r\nf := plausible.Filter{\r\n  Properties: plausible.Properties{\r\n    {Name:  plausible.VisitOs, Value: \"Windows\"},\r\n    {Name:  plausible.VisitBrowser, Value: \"Firefox\"},\r\n  }\r\n}\r\n```\r\n\r\nFor each property, you can provide a set of values, separated by `|` to make the filter match any of the provided\r\nvalues. For instance, to filter the data by visits of users using firefox in either linux or windows, we can do:\r\n\r\n```go\r\nf := plausible.NewFilter().ByVisitOs(\"Windows|Linux\").ByVisitBrowser(\"Firefox\")\r\n```\r\n\r\nTo know more about properties, see [Plausible Docs: Filtering](https://plausible.io/docs/stats-api#filtering)\r\n\r\n### \u003ca name=\"metrics\"\u003e\u003c/a\u003e Metrics\r\n\r\nMetrics are aggregate information about the data. All queries have the option for you to choose the metrics you want to\r\nsee included in the results.\r\n\r\nThere are 6 metrics currently that you can ask the results for: number of visitors, number of page views, visit duration, bounce rate, visits and events.\r\nIn this library, these metrics are represented by\r\nthe [Metric](https://pkg.go.dev/github.com/andrerfcsantos/go-plausible/plausible#Metric)\r\ntype. There are 6 constants of type `Metric`, each one representing one of the 6 metrics: `Visitors`,\r\n`PageViews`, `BounceRate`, `VisitDuration`, `Events` and `Visits`\r\n\r\nFor instance, if for a query you only want information about the pageviews and number of visitors, you can pass this to\r\nthe query in the metrics parameter:\r\n\r\n```go\r\nmetrics := plausible.Metrics {\r\n\tplausible.Visitors,\r\n\tplausible.PageViews,\r\n},\r\n```\r\n\r\nFor convenience, when you want to get information about all metrics, there's a function `AllMetrics()`\r\nthat returns all the 6 metrics. However, please note that not all queries support requests for all metrics. For that\r\nreason, use requests for all metrics with caution. If you try to use a metric in a query that does not support that\r\nmetric, you will get an error message saying which property was at fault.\r\n\r\n### \u003ca name=\"time-intervals\"\u003e\u003c/a\u003e Time Intervals\r\n\r\nTime intervals are used for [time series queries](#timeseries-queries) to specify the interval of time between 2\r\nconsecutive data points.\r\n\r\nA time interval is represented by\r\nthe [TimeInterval](https://pkg.go.dev/github.com/andrerfcsantos/go-plausible/plausible#TimeInterval) type. There are\r\ncurrently 2 time intervals: date and month. This library also exposes two `TimeInterval`\r\nconstants for these value: `DateInterval` and `MonthInterval` respectively.\r\n\r\nA `MonthInterval` means a month of difference between data points. For instance, if you ask for time series data over\r\nthe last 6 months with a month interval, this means you will get 6 data points back - 1 for each month.\r\n\r\nA `DateInterval`, depending on the query, means a day or an hour of difference between each data point. For instance, if\r\nyou ask for time series data over the last 30 days with a date interval, you will get 30 data points back - 1 for each\r\nday. However, with a `DateInterval`, when the period of the time series refers to a day, for instance \"today\", the data\r\npoints will actually have 1 hour of interval between them. You can check the `Date` string field of each data point to\r\nknow about which date/hour the data refers to.\r\n\r\n## \u003ca name=\"queries\"\u003e\u003c/a\u003e Queries\r\n\r\nThere are 4 types of queries supported by the API:\r\n\r\n* Current Visitors\r\n* Aggregate Queries\r\n* Timeseries Queries\r\n* Breakdown Queries\r\n\r\n### \u003ca name=\"current-visitors\"\u003e\u003c/a\u003e Current Visitors\r\n\r\nThis is the most straight forward query - for a given site return the number of current visitors:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\t// Get an handler to perform queries for a given site\r\n\tmysite := client.Site(\"example.com\")\r\n\r\n\tvisitors, err := mysite.CurrentVisitors()\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\r\n\tfmt.Printf(\"Site %s has %d current visitors!\\n\", mysite.ID(), visitors)\r\n}\r\n```\r\n\r\n### \u003ca name=\"aggregate-queries\"\u003e\u003c/a\u003e Aggregate Queries\r\n\r\nAn aggregate query reports data for metrics aggregated over a period of time.\r\n\r\nA query like \"the total number of visitors today\" fall into this category, where the period is a day (in this case \"\r\ntoday\") and the metric is the number of visitors.\r\n\r\nHere's how to write this query:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\t// Get an handler to perform queries for a given site\r\n\tmysite := client.Site(\"example.com\")\r\n\r\n\t// Build query\r\n\ttodaysVisitorsQuery := plausible.AggregateQuery{\r\n\t\tPeriod: plausible.DayPeriod(),\r\n\t\tMetrics: plausible.Metrics{\r\n\t\t\tplausible.Visitors,\r\n\t\t},\r\n\t}\r\n\r\n\t// Make query\r\n\tresult, err := mysite.Aggregate(todaysVisitorsQuery)\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\r\n\tfmt.Printf(\"Total visitors of %s today: %d\\n\", mysite.ID(), result.Visitors)\r\n}\r\n```\r\n\r\n### \u003ca name=\"timeseries-queries\"\u003e\u003c/a\u003e Time Series Queries\r\n\r\nA time series query reports a list of data points over a period of time, where each data point contains data about\r\nmetrics for that period of time.\r\n\r\nA query like \"the number of visitors and page views for each day in the 7 days before the 1st of February 2021\"\r\nfalls into this category.\r\n\r\nThis is how to write this query:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\t// Get an handler to perform queries for a given site\r\n\tmysite := client.Site(\"example.com\")\r\n\r\n\t// Build query\r\n\ttsQuery := plausible.TimeseriesQuery{\r\n\t\tPeriod: plausible.Last7Days().FromDate(plausible.Date{Day: 1, Month: 2, Year: 2021}),\r\n\t\tMetrics: plausible.Metrics{\r\n\t\t\tplausible.Visitors,\r\n\t\t\tplausible.PageViews,\r\n\t\t},\r\n\t}\r\n\r\n\t// Make query\r\n\tqueryResults, err := mysite.Timeseries(tsQuery)\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\r\n\t// Iterate over the data points\r\n\tfor _, stat := range queryResults {\r\n\t\tfmt.Printf(\"Date: %s | Visitors: %d | Pageviews: %d\\n\",\r\n\t\t\tstat.Date, stat.Visitors, stat.Pageviews)\r\n\t}\r\n\r\n}\r\n```\r\n\r\n### \u003ca name=\"breakdown-queries\"\u003e\u003c/a\u003e Breakdown Queries\r\n\r\nA breakdown query reports stats for the value of a given property over a period of time.\r\n\r\nFor instance, a query like \"over the last 7 days what are the number of visitors and page views for each page of my\r\nsite\" falls into this category.\r\n\r\nHere's how to write such query:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\t// Get an handler to perform queries for a given site\r\n\tmysite := client.Site(\"example.com\")\r\n\r\n\t// Build query\r\n\tpageBreakdownQuery := plausible.BreakdownQuery{\r\n\t\tProperty: plausible.EventPage,\r\n\t\tPeriod:   plausible.Last7Days(),\r\n\t\tMetrics: plausible.Metrics{\r\n\t\t\tplausible.Visitors,\r\n\t\t\tplausible.PageViews,\r\n\t\t},\r\n\t}\r\n\r\n\t// Make query\r\n\tpageBreakdown, err := mysite.Breakdown(pageBreakdownQuery)\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\r\n\t// Iterate the results\r\n\tfor _, stat := range pageBreakdown {\r\n\t\tfmt.Printf(\"Page: %s | Visitors: %d | Pageviews: %d \\n\",\r\n\t\t\tstat.Page, stat.Visitors, stat.Pageviews)\r\n\t}\r\n\r\n}\r\n```\r\n\r\n## \u003ca name=\"site-provisioning-api\"\u003e\u003c/a\u003e Site Provisioning API\r\n\r\nThis wrapper has support for the [site provisioning API](https://plausible.io/docs/sites-api).\r\n\r\nHowever, note that this API is still private and requires a special token for the requests mentioned below to work. Make\r\nsure you have a token with permissions for the site provisioning API before attempting to make these requests. You can\r\ngo here to know more about how to get a token for this API:\r\n\r\n* [Plausible Docs: Site Provisioning API](https://plausible.io/docs/sites-api)\r\n\r\n### \u003ca name=\"provisioning-api-get-sites\"\u003e\u003c/a\u003e List sites\r\n\r\nGets a list of existing sites your Plausible account can access.\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\t// Warning: This token must have permissions to the site provisioning API\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\tsites, err := client.ListSites()\r\n\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\r\n\tfmt.Printf(\"Sites %s\\n\", sites.Sites)\r\n}\r\n```\r\n\r\nIf the response contains a lot of sites, it will be paginated. To access other pages, use the pagination options:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n    \"github.com/andrerfcsantos/go-plausible/plausible/urlmaker/pagination\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\t// Warning: This token must have permissions to the site provisioning API\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n    sites, err := client.ListSites(\r\n      pagination.After(\"awebsite\"),\r\n      pagination.Before(\"otherwebsite\"),\r\n      pagination.Limit(20),\r\n    )\r\n\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\r\n\tfmt.Printf(\"Sites %s\\n\", sites.Sites)\r\n}\r\n```\r\n\r\n\r\n\r\n### \u003ca name=\"provisioning-api-get-site\"\u003e\u003c/a\u003e Get site\r\n\r\nGets details of a site. Your Plausible account must have access to it.\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\t// Warning: This token must have permissions to the site provisioning API\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\t// Get an handler to perform queries for a given site\r\n\tmysite := client.Site(\"example.com\")\r\n\r\n\tsiteResult, err := mysite.Details()\r\n\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\r\n\tfmt.Printf(\"Site %v\\n\", siteResult)\r\n}\r\n```\r\n\r\n### \u003ca name=\"provisioning-api-shared-links\"\u003e\u003c/a\u003e Get or create Shared Links\r\n\r\nShared Links are URLs that you can generate to give others access to your dashboards.\r\n\r\nYou can use `SharedLink()` to get information for a link or create one with a given name. The call to get and create a\r\nshared link it's the same - if a link with the given name already exists, it'll simply get the information for the\r\nexistent link. If the link does not exist, this call will create it and return the information of the newly created\r\nlink.\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\t// Warning: This token must have permissions to the site provisioning API\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\t// Get an handler to perform queries for a given site\r\n\tmysite := client.Site(\"example.com\")\r\n\r\n\tsl := plausible.SharedLinkRequest{\r\n\t\tName: \"Friends Link\",\r\n\t}\r\n\tslResult, err := mysite.SharedLink(sl)\r\n\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\r\n\tfmt.Printf(\"Name: %s | URL: %s\\n\", slResult.Name, slResult.URL)\r\n\r\n}\r\n```\r\n\r\n### \u003ca name=\"provisioning-api-create-new-sites\"\u003e\u003c/a\u003e Create new sites\r\n\r\nIt's also possible to create new sites using the site provisioning API. Attempting to create a site that already exists\r\nwill result in an error.\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"github.com/andrerfcsantos/go-plausible/plausible\"\r\n)\r\n\r\nfunc main() {\r\n\t// Create a client with an API token\r\n\t// Warning: This token must have permissions to the site provisioning API\r\n\tclient := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\tnewSiteRequest := plausible.CreateSiteRequest{\r\n\t\tDomain:   \"mynewsite.com\",\r\n\t\tTimezone: \"Europe/Lisbon\",\r\n\t}\r\n\r\n\t// Note that we call CreateNewSite directly on the client,\r\n\t// and not on a site like the majority of requests\r\n\tsiteResult, err := client.CreateNewSite(newSiteRequest)\r\n\r\n\tif err != nil {\r\n\t\t// handle error\r\n\t}\r\n\tfmt.Printf(\"Domain: %s | Timezone: %s\\n\", siteResult.Domain, siteResult.Timezone)\r\n\r\n}\r\n```\r\n\r\n## \u003ca name=\"events-api\"\u003e\u003c/a\u003e Events API\r\n\r\nPush events with `site.PushEvent()`\r\n\r\n```go\r\nfunc main() {\r\n    // Create a client with an API token\r\n    client := plausible.NewClient(\"\u003cyour_api_token\u003e\")\r\n\r\n\t// Get an handler to perform queries for a given site\r\n\tmysite := client.Site(\"example.com\")\r\n\t\r\n      e := plausible.EventRequest {\r\n\t\t  EventData: EventData{\r\n            Domain:  \"example.org\",\r\n            Name:    \"pageview\",\r\n            URL:     \"https://example.com/awesome_page\",\r\n\t\t  }\r\n\t\t  UserAgent:  \"user-agent\"\r\n      }\r\n\r\n      _, err := client.PushEvent(e)\r\n      if err != nil {\r\n        // handle error\r\n      }\r\n\t}\r\n}\r\n```\r\n\r\n## \u003ca name=\"tests\"\u003e\u003c/a\u003e Tests\r\n\r\nThis project has tests in the form of Unit tests and Integration tests.\r\n\r\n### \u003ca name=\"unit-tests\"\u003e\u003c/a\u003e Unit Tests\r\n\r\nUnit tests are the easiest to run as they don't require any setup and do not attempt to make requests over the internet.\r\n\r\nUnit tests start with `TestUnit`. This means that to run just the unit tests, you can do:\r\n\r\n```bash\r\ngo test github.com/andrerfcsantos/go-plausible/plausible -run ^TestUnit\r\n```\r\n\r\n### \u003ca name=\"integration-tests\"\u003e\u003c/a\u003e Integration Tests\r\n\r\nIntegration tests attempt to make calls to the API. Because of this, they require configuration in the form of\r\nenvironment variables. Set these environment variables before attempting to run the integration tests:\r\n\r\n* `PLAUSIBLE_TOKEN` - API token to be used in the integration tests\r\n* `PLAUSIBLE_DOMAINS` - A domain or a comma separated list of domains. The first domain on the list will be used to test\r\n  queries.\r\n\r\nIntegration tests start with the name `TestIntegration`. With these variable set, you can run only the integration tests\r\nwith:\r\n\r\n```bash\r\ngo test github.com/andrerfcsantos/go-plausible/plausible -run ^TestIntegration\r\n```\r\n\r\nTo run the unit tests, and the integration tests, just omit the `-run` flag:\r\n\r\n```bash\r\ngo test github.com/andrerfcsantos/go-plausible/plausible\r\n```\r\n\r\nThese integration tests do not include tests that require the site provisioning API. See below you to active tests for\r\nthe site provisioning API.\r\n\r\n### \u003ca name=\"integration-tests-provisioning\"\u003e\u003c/a\u003e Integration Tests with the provisioning API\r\n\r\nIntegration tests to the site provisioning API are disabled by default.\r\n\r\nThere are a couple of reasons for this:\r\n\r\n* The provisioning API is still private and requires a token with special permissions. Most users will use a regular API\r\n  token, so these tests will not be relevant to them.\r\n\r\n* The provisioning API allows the creation of sites and shared links, but the only way to reverse the actions of the API\r\n  is by manually deleting them via the dashboard. This also means that **the cleanup for these tests must be done\r\n  manually**.\r\n\r\nWith that said, if you really need to run these tests, set the following environment variable in addition to `PLAUSIBLE_TOKEN`\r\nand `PLAUSIBLE_DOMAINS`:\r\n\r\n* `PLAUSIBLE_PROVISIONING_TOKEN` - this must be set to an API token with permissions to the provisioning API.\r\n\r\nWith this variable set up, to run all tests (unit+integration tests) including the integration tests of the provisioning\r\nAPI, add the flag `provisioning` to the `go test command`:\r\n\r\n```bash\r\ngo test github.com/andrerfcsantos/go-plausible/plausible -flags=provisioning\r\n```\r\n\r\n## \u003ca name=\"bugs-feedback\"\u003e\u003c/a\u003e Bugs and Feedback\r\n\r\nIf you encounter any bugs or have any comment or suggestion, please post them in\r\nthe [Issues section](https://github.com/andrerfcsantos/go-plausible/issues) of this repository.\r\n\r\n## \u003ca name=\"contributing\"\u003e\u003c/a\u003e Contributing\r\n\r\nAll contributions are welcome!\r\n\r\nFeel free to open PR's or post suggestions on\r\nthe [Issues section](https://github.com/andrerfcsantos/go-plausible/issues).\r\n\r\n## \u003ca name=\"license\"\u003e\u003c/a\u003e License\r\n\r\nThis project uses the [MIT License](https://github.com/andrerfcsantos/go-plausible/blob/main/LICENSE)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrerfcsantos%2Fgo-plausible","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrerfcsantos%2Fgo-plausible","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrerfcsantos%2Fgo-plausible/lists"}