Skip to content

Commit

Permalink
Add support to record events (#4)
Browse files Browse the repository at this point in the history
* Add support to record events in Plausible

For: #1

* Finish up events API

---------

Co-authored-by: André Santos <andrerfcsantos@gmail.com>
  • Loading branch information
till and andrerfcsantos authored Aug 3, 2024
1 parent 71c3e8a commit aabdf92
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 4 deletions.
34 changes: 31 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ It currently supports the full API of Plausible, which includes:
* [Get/Create Shared Links](#provisioning-api-shared-links)
* [Create new sites](#provisioning-api-create-new-sites)

* [Events API](#events-api)

* [Tests](#tests)
* [Unit Tests](#unit-tests)
* [Integration Tests](#integration-tests)
Expand Down Expand Up @@ -63,9 +65,6 @@ func main() {

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

// Use 'mysite' and the 'myothersite' handlers to query stats for the sites
// ...
}
```

Expand Down Expand Up @@ -489,6 +488,35 @@ func main() {
}
```

## <a name="events-api"></a> Events API

Push events with `site.PushEvent()`

```go
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
}
}
}
```

## <a name="tests"></a> Tests

This project has tests in the form of Unit tests and Integration tests.
Expand Down
11 changes: 10 additions & 1 deletion plausible/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (c *Client) acquireRequest(method, endpoint string, queries QueryArgs, form
req.URI().QueryArgs().Add(q.Name, q.Value)
}

if formData.Count() > 0 {
if formData != nil && formData.Count() > 0 {
body := &bytes.Buffer{}
mpwriter := multipart.NewWriter(body)

Expand Down Expand Up @@ -149,3 +149,12 @@ func (c *Client) CreateNewSite(siteRequest CreateSiteRequest) (CreateSiteResult,

return res, nil
}

// PushEvent records an event on plausible
func (c *Client) PushEvent(ev EventRequest) ([]byte, error) {
req, err := c.acquireEventRequest(ev)
if err != nil {
return nil, fmt.Errorf("acquiring event request from client: %w", err)
}
return doRequest(s.httpClient, req)
}
84 changes: 84 additions & 0 deletions plausible/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package plausible

import (
"bytes"
"encoding/json"
"fmt"
"github.com/valyala/fasthttp"
)

// EventData represents the data of an event
type EventData struct {
// Domain of the site
Domain string `json:"domain"`
// Name is the name of the event, e.g. 'pageview', otherwise a custom event
Name string `json:"name"`

// URL of the current request
URL string `json:"url"`

// Referrer to be associated with the event
Referrer string `json:"referrer,omitempty"`
// Props of the event
Props map[string]string `json:"props,omitempty"`
// Revenue associated with the event
Revenue Revenue `json:"revenue,omitempty"`
}

// EventRequest represents the request for an event
type EventRequest struct {
EventData
// User Agent to be associated with request event.
// This field is mandatory.
UserAgent string
// X-Forwarded-For header to be sent with the event. This field is optional.
XForwardedFor string
// AdditionalHeaders are additional headers to be included in the request. This field is optional.
AdditionalHeaders map[string]string
// IsDebuggingRequest tells if this is a debugging request. This field is optional.
IsDebuggingRequest bool
}

// Revenue represents the revenue associated with an event
type Revenue struct {
// Currency is
Currency string `json:"currency"`
Amount string `json:"amount"`
}

func (c *Client) acquireEventRequest(request EventRequest) (*fasthttp.Request, error) {
if request.UserAgent == "" {

return nil, fmt.Errorf("missing user agent information for the event request")
}

req, err := c.acquireRequest("POST", "/api/event", nil, nil)
if err != nil {

return nil, fmt.Errorf("acquiring request from client for /api/event: %w", err)
}

req.Header.Add("Content-Type", "application/json")
req.Header.Add("User-Agent", request.UserAgent)

if request.IsDebuggingRequest {
req.Header.Add("X-Debug-Request", "true")
}

if request.XForwardedFor != "" {
req.Header.Add("X-Forwarded-For", request.XForwardedFor)
}

for header, value := range request.AdditionalHeaders {
req.Header.Add(header, value)
}

body := new(bytes.Buffer)
err = json.NewEncoder(body).Encode(request.EventData)
if err != nil {
return nil, fmt.Errorf("encoding request body for event request: %w", err)
}

req.SetBody(body.Bytes())
return req, nil
}

0 comments on commit aabdf92

Please sign in to comment.