Skip to content

andrerfcsantos/go-plausible

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-plausible - Go Wrapper for the Plausible API

Go Reference Go Report Card

Go wrapper/client for the Plausible API.

It currently supports the full API of Plausible, which includes:

Table of Contents

Basic Usage

import "github.com/andrerfcsantos/go-plausible/plausible"

To use this client, you'll need an API token, which you can get from the Plausible Dashboard.

With the API token, create a client and get a handler for one or more sites:

package main

import "github.com/andrerfcsantos/go-plausible/plausible"

func main() {
	// Create a client with an API token
	client := plausible.NewClient("<your_api_token>")

	// Get an handler to perform queries for a given site
	mysite := client.Site("example.com")

	// You can reuse the same client to get handlers for additional sites
	myothersite := client.Site("otherexample.com")
}

Concepts

There a few concepts that are useful to know before using this wrapper or the Plausible API.

Time Periods

When requesting aggregate information to the API, it's only possible to get data for a given period of time. For instance, "the last 7 days", "the last month" or "the current day" are examples of time periods.

All time periods are relative to a date. When the date information is missing from a time period, the date is assumed to be "today". It's also possible to specify a time period between two specific dates.

Time periods are represented in this library by the TimePeriod type.

Unless you want low-level access to the API, you don't need to create a TimePeriod directly, and you can just use the helper functions to build a time period:

// Get the period for the last 6 months from today
p := plausible.Last6Months()

To associate a date to a time period, chain the result with FromDate() or OfDate():

// Get the period for the last 12 months from the 1st of January 2021
p := plausible.Last12Months().FromDate(plausible.Date{Day:1, Month: 1, Year: 2021})

To make a custom period between 2 dates:

// Get the period for the first 15 days of 2021
p := plausible.CustomPeriod(plausible.Date{Day:1, Month: 1, Year: 2021}, plausible.Date{Day:15, Month: 1, Year: 2021})

To know more about time periods, see Plausible Docs: Time Periods

Properties

Each pageview or custom event has some properties associated with it. These properties can be used when querying the API to filter the results.

Properties are represented in this library by the Property type. Properties have a name and value. The name of a property is represented by the PropertyName type. Typically, most users won't need to make custom property names and can just use the constant PropertyName values declared at the top-level of the package like VisitOs or VisitBrowser.

To make a custom PropertyName, the function CustomPropertyName() can be used:

pName := plausible.CustomPropertyName("myevent")

Obtaining custom property names via this method is needed when you have custom events and want to refer to those events as a property.

To easily make a custom property with a name and a value, you can use the CustomProperty function:

p := plausible.CustomProperty("myevent", "myeventvalue")

To know more about properties, see Plausible Docs: Properties

Filters

Filters allow drilling down and segment the data to which the results refer to. All queries for data accept an optional filter argument.

In this library, filters are represented by the Filter type.

A filter consists of a simple list of properties by which you want to filter. For instance, to create a filter that filters all visits by their operating system, you can do:

f := plausible.NewFilter().ByVisitOs("Windows")

You can add more properties to the filter by chaining calls:

f := plausible.NewFilter().ByVisitOs("Windows").ByVisitBrowser("Firefox")

This will filter the results based on the visits from Windows users that were using Firefox. So, a filter basically consists of a logic AND of all its properties.

You can also instantiate a filter directly if you want a more low-level access to the API. For instance, this an alternative way to write the filter above:

f := plausible.Filter{
  Properties: plausible.Properties{
    {Name:  plausible.VisitOs, Value: "Windows"},
    {Name:  plausible.VisitBrowser, Value: "Firefox"},
  }
}

For each property, you can provide a set of values, separated by | to make the filter match any of the provided values. For instance, to filter the data by visits of users using firefox in either linux or windows, we can do:

f := plausible.NewFilter().ByVisitOs("Windows|Linux").ByVisitBrowser("Firefox")

To know more about properties, see Plausible Docs: Filtering

Metrics

Metrics are aggregate information about the data. All queries have the option for you to choose the metrics you want to see included in the results.

There 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. In this library, these metrics are represented by the Metric type. There are 6 constants of type Metric, each one representing one of the 6 metrics: Visitors, PageViews, BounceRate, VisitDuration, Events and Visits

For instance, if for a query you only want information about the pageviews and number of visitors, you can pass this to the query in the metrics parameter:

metrics := plausible.Metrics {
	plausible.Visitors,
	plausible.PageViews,
},

For convenience, when you want to get information about all metrics, there's a function AllMetrics() that returns all the 6 metrics. However, please note that not all queries support requests for all metrics. For that reason, use requests for all metrics with caution. If you try to use a metric in a query that does not support that metric, you will get an error message saying which property was at fault.

Time Intervals

Time intervals are used for time series queries to specify the interval of time between 2 consecutive data points.

A time interval is represented by the TimeInterval type. There are currently 2 time intervals: date and month. This library also exposes two TimeInterval constants for these value: DateInterval and MonthInterval respectively.

A MonthInterval means a month of difference between data points. For instance, if you ask for time series data over the last 6 months with a month interval, this means you will get 6 data points back - 1 for each month.

A DateInterval, depending on the query, means a day or an hour of difference between each data point. For instance, if you ask for time series data over the last 30 days with a date interval, you will get 30 data points back - 1 for each day. However, with a DateInterval, when the period of the time series refers to a day, for instance "today", the data points will actually have 1 hour of interval between them. You can check the Date string field of each data point to know about which date/hour the data refers to.

Queries

There are 4 types of queries supported by the API:

  • Current Visitors
  • Aggregate Queries
  • Timeseries Queries
  • Breakdown Queries

Current Visitors

This is the most straight forward query - for a given site return the number of current visitors:

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
	// Create a client with an API token
	client := plausible.NewClient("<your_api_token>")

	// Get an handler to perform queries for a given site
	mysite := client.Site("example.com")

	visitors, err := mysite.CurrentVisitors()
	if err != nil {
		// handle error
	}

	fmt.Printf("Site %s has %d current visitors!\n", mysite.ID(), visitors)
}

Aggregate Queries

An aggregate query reports data for metrics aggregated over a period of time.

A query like "the total number of visitors today" fall into this category, where the period is a day (in this case " today") and the metric is the number of visitors.

Here's how to write this query:

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
	// Create a client with an API token
	client := plausible.NewClient("<your_api_token>")

	// Get an handler to perform queries for a given site
	mysite := client.Site("example.com")

	// Build query
	todaysVisitorsQuery := plausible.AggregateQuery{
		Period: plausible.DayPeriod(),
		Metrics: plausible.Metrics{
			plausible.Visitors,
		},
	}

	// Make query
	result, err := mysite.Aggregate(todaysVisitorsQuery)
	if err != nil {
		// handle error
	}

	fmt.Printf("Total visitors of %s today: %d\n", mysite.ID(), result.Visitors)
}

Time Series Queries

A time series query reports a list of data points over a period of time, where each data point contains data about metrics for that period of time.

A query like "the number of visitors and page views for each day in the 7 days before the 1st of February 2021" falls into this category.

This is how to write this query:

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
	// Create a client with an API token
	client := plausible.NewClient("<your_api_token>")
	// Get an handler to perform queries for a given site
	mysite := client.Site("example.com")

	// Build query
	tsQuery := plausible.TimeseriesQuery{
		Period: plausible.Last7Days().FromDate(plausible.Date{Day: 1, Month: 2, Year: 2021}),
		Metrics: plausible.Metrics{
			plausible.Visitors,
			plausible.PageViews,
		},
	}

	// Make query
	queryResults, err := mysite.Timeseries(tsQuery)
	if err != nil {
		// handle error
	}

	// Iterate over the data points
	for _, stat := range queryResults {
		fmt.Printf("Date: %s | Visitors: %d | Pageviews: %d\n",
			stat.Date, stat.Visitors, stat.Pageviews)
	}

}

Breakdown Queries

A breakdown query reports stats for the value of a given property over a period of time.

For instance, a query like "over the last 7 days what are the number of visitors and page views for each page of my site" falls into this category.

Here's how to write such query:

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
	// Create a client with an API token
	client := plausible.NewClient("<your_api_token>")

	// Get an handler to perform queries for a given site
	mysite := client.Site("example.com")

	// Build query
	pageBreakdownQuery := plausible.BreakdownQuery{
		Property: plausible.EventPage,
		Period:   plausible.Last7Days(),
		Metrics: plausible.Metrics{
			plausible.Visitors,
			plausible.PageViews,
		},
	}

	// Make query
	pageBreakdown, err := mysite.Breakdown(pageBreakdownQuery)
	if err != nil {
		// handle error
	}

	// Iterate the results
	for _, stat := range pageBreakdown {
		fmt.Printf("Page: %s | Visitors: %d | Pageviews: %d \n",
			stat.Page, stat.Visitors, stat.Pageviews)
	}

}

Site Provisioning API

This wrapper has support for the site provisioning API.

However, note that this API is still private and requires a special token for the requests mentioned below to work. Make sure you have a token with permissions for the site provisioning API before attempting to make these requests. You can go here to know more about how to get a token for this API:

List sites

Gets a list of existing sites your Plausible account can access.

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
	// Create a client with an API token
	// Warning: This token must have permissions to the site provisioning API
	client := plausible.NewClient("<your_api_token>")

	sites, err := client.ListSites()

	if err != nil {
		// handle error
	}

	fmt.Printf("Sites %s\n", sites.Sites)
}

If the response contains a lot of sites, it will be paginated. To access other pages, use the pagination options:

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
    "github.com/andrerfcsantos/go-plausible/plausible/urlmaker/pagination"
)

func main() {
	// Create a client with an API token
	// Warning: This token must have permissions to the site provisioning API
	client := plausible.NewClient("<your_api_token>")

    sites, err := client.ListSites(
      pagination.After("awebsite"),
      pagination.Before("otherwebsite"),
      pagination.Limit(20),
    )

	if err != nil {
		// handle error
	}

	fmt.Printf("Sites %s\n", sites.Sites)
}

Get site

Gets details of a site. Your Plausible account must have access to it.

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
	// Create a client with an API token
	// Warning: This token must have permissions to the site provisioning API
	client := plausible.NewClient("<your_api_token>")

	// Get an handler to perform queries for a given site
	mysite := client.Site("example.com")

	siteResult, err := mysite.Details()

	if err != nil {
		// handle error
	}

	fmt.Printf("Site %v\n", siteResult)
}

Get or create Shared Links

Shared Links are URLs that you can generate to give others access to your dashboards.

You can use SharedLink() to get information for a link or create one with a given name. The call to get and create a shared link it's the same - if a link with the given name already exists, it'll simply get the information for the existent link. If the link does not exist, this call will create it and return the information of the newly created link.

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
	// Create a client with an API token
	// Warning: This token must have permissions to the site provisioning API
	client := plausible.NewClient("<your_api_token>")

	// Get an handler to perform queries for a given site
	mysite := client.Site("example.com")

	sl := plausible.SharedLinkRequest{
		Name: "Friends Link",
	}
	slResult, err := mysite.SharedLink(sl)

	if err != nil {
		// handle error
	}

	fmt.Printf("Name: %s | URL: %s\n", slResult.Name, slResult.URL)

}

Create new sites

It's also possible to create new sites using the site provisioning API. Attempting to create a site that already exists will result in an error.

package main

import (
	"fmt"
	"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
	// Create a client with an API token
	// Warning: This token must have permissions to the site provisioning API
	client := plausible.NewClient("<your_api_token>")

	newSiteRequest := plausible.CreateSiteRequest{
		Domain:   "mynewsite.com",
		Timezone: "Europe/Lisbon",
	}

	// Note that we call CreateNewSite directly on the client,
	// and not on a site like the majority of requests
	siteResult, err := client.CreateNewSite(newSiteRequest)

	if err != nil {
		// handle error
	}
	fmt.Printf("Domain: %s | Timezone: %s\n", siteResult.Domain, siteResult.Timezone)

}

Events API

Push events with site.PushEvent()

func main() {
    // Create a client with an API token
    client := plausible.NewClient("<your_api_token>")

	// Get an handler to perform queries for a given site
	mysite := client.Site("example.com")
	
      e := plausible.EventRequest {
		  EventData: EventData{
            Domain:  "example.org",
            Name:    "pageview",
            URL:     "https://example.com/awesome_page",
		  }
		  UserAgent:  "user-agent"
      }

      _, err := client.PushEvent(e)
      if err != nil {
        // handle error
      }
	}
}

Tests

This project has tests in the form of Unit tests and Integration tests.

Unit Tests

Unit tests are the easiest to run as they don't require any setup and do not attempt to make requests over the internet.

Unit tests start with TestUnit. This means that to run just the unit tests, you can do:

go test github.com/andrerfcsantos/go-plausible/plausible -run ^TestUnit

Integration Tests

Integration tests attempt to make calls to the API. Because of this, they require configuration in the form of environment variables. Set these environment variables before attempting to run the integration tests:

  • PLAUSIBLE_TOKEN - API token to be used in the integration tests
  • PLAUSIBLE_DOMAINS - A domain or a comma separated list of domains. The first domain on the list will be used to test queries.

Integration tests start with the name TestIntegration. With these variable set, you can run only the integration tests with:

go test github.com/andrerfcsantos/go-plausible/plausible -run ^TestIntegration

To run the unit tests, and the integration tests, just omit the -run flag:

go test github.com/andrerfcsantos/go-plausible/plausible

These integration tests do not include tests that require the site provisioning API. See below you to active tests for the site provisioning API.

Integration Tests with the provisioning API

Integration tests to the site provisioning API are disabled by default.

There are a couple of reasons for this:

  • The provisioning API is still private and requires a token with special permissions. Most users will use a regular API token, so these tests will not be relevant to them.

  • The provisioning API allows the creation of sites and shared links, but the only way to reverse the actions of the API is by manually deleting them via the dashboard. This also means that the cleanup for these tests must be done manually.

With that said, if you really need to run these tests, set the following environment variable in addition to PLAUSIBLE_TOKEN and PLAUSIBLE_DOMAINS:

  • PLAUSIBLE_PROVISIONING_TOKEN - this must be set to an API token with permissions to the provisioning API.

With this variable set up, to run all tests (unit+integration tests) including the integration tests of the provisioning API, add the flag provisioning to the go test command:

go test github.com/andrerfcsantos/go-plausible/plausible -flags=provisioning

Bugs and Feedback

If you encounter any bugs or have any comment or suggestion, please post them in the Issues section of this repository.

Contributing

All contributions are welcome!

Feel free to open PR's or post suggestions on the Issues section.

License

This project uses the MIT License