> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apitally.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Setup guide for Echo

> Just a few simple steps to get started with Apitally.

export const language_0 = "go"

export const framework_0 = "Echo"

This page guides you through the steps of configuring your [Echo](https://echo.labstack.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup).

Once you're done with this guide, you will be able to:

* Get detailed metrics on API usage, errors, and performance
* Track API adoption and usage by individual consumers
* Log individual API requests, responses, and correlated application logs
* See what's causing slow API requests with traces
* Monitor uptime and set up custom alerts

## Create app

To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select {framework_0} as your framework.

<img src="https://assets.apitally.io/docs/2025-12-08/create-app.webp" alt="Create app" className="rounded-xl" />

You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults.

After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project.

<Note>
  The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data.
</Note>

## Add middleware

Add the [Apitally SDK](/sdk-reference/go/overview) to the dependencies in your Echo project.

<CodeGroup>
  ```shell v5 theme={null}
  go get github.com/apitally/apitally-go/echo-v5
  ```

  ```shell v4 theme={null}
  go get github.com/apitally/apitally-go/echo-v4
  ```
</CodeGroup>

Add the Apitally middleware to your Echo application and provide the `ClientId` for your app.
You'll find the `ClientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app.

<CodeGroup>
  ```go v5 theme={null}
  package main

  import (
      apitally "github.com/apitally/apitally-go/echo-v5"
      "github.com/labstack/echo/v5"
  )

  func main() {
      e := echo.New()

      config := apitally.NewConfig("your-client-id")
      config.Env = "dev" // or "prod" etc.

      e.Use(apitally.Middleware(e, config))

      // ... rest of your code ...
  }
  ```

  ```go v4 theme={null}
  package main

  import (
      apitally "github.com/apitally/apitally-go/echo-v4"
      "github.com/labstack/echo/v4"
  )

  func main() {
      e := echo.New()

      config := apitally.NewConfig("your-client-id")
      config.Env = "dev" // or "prod" etc.

      e.Use(apitally.Middleware(e, config))

      // ... rest of your code ...
  }
  ```
</CodeGroup>

<div style={{ marginTop: "-0.5rem" }}>
  <Note>
    Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
  </Note>
</div>

Deploy your application with these changes, or restart if you're testing locally.

<Check>
  At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard.
</Check>

## Identify consumers

To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application.

In most cases, use the authenticated identity to identify the consumer.
The identifier should be a string, such as a username, email address, or any other unique identifier.

Optionally, you can also provide a display name and group for each consumer.

To associate requests with consumers, use the `SetConsumerIdentifier` or `SetConsumer` function, for example in a middleware.

<CodeGroup>
  ```go {8} Identifier only theme={null}
  func authMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
      return func(c *echo.Context) error {
          // Your authentication logic here
          // ...

          if user.IsAuthenticated() {
              // Use the authenticated identity as consumer identifier
              apitally.SetConsumerIdentifier(c, user.Identifier)
          }
          return next(c)
      }
  }
  ```

  ```go {7-11} With name and group theme={null}
  func authMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
      return func(c *echo.Context) error {
          // Your authentication logic here
          // ...

          if user.IsAuthenticated() {
              apitally.SetConsumer(c, apitally.Consumer{
                  Identifier: user.Email,
                  Name:       user.Name, // optional
                  Group:      user.Group, // optional
              })
          }
          return next(c)
      }
  }
  ```
</CodeGroup>

<Check>
  The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer.
</Check>

## Capture validation errors

If you're using the `go-playground/validator/v10` package to validate incoming data, you can use the `CaptureValidationError` function to record validation errors.
This gives you visibility into the validation errors returned by your API endpoints.

```go {25} theme={null}
package main

import (
    apitally "github.com/apitally/apitally-go/echo-v5"
    "github.com/labstack/echo/v5"
    "github.com/go-playground/validator/v10"
)

type HelloRequest struct {
    Name string `json:"name" validate:"required"`
}

func main() {
    e := echo.New()
    validate := validator.New()

    // ...

    e.POST("/hello", func(c *echo.Context) error {
        var req HelloRequest
        if err := c.Bind(&req); err != nil {
            return c.JSON(400, map[string]string{"error": err.Error()})
        }
        if err := validate.Struct(req); err != nil {
            apitally.CaptureValidationError(c, err)
            return c.JSON(400, map[string]string{"error": err.Error()})
        }
        return c.JSON(200, map[string]string{"message": "Hello, " + req.Name + "!"})
    })

    // ...
}
```

## Configure request logging

Logging of individual requests and responses is disabled by default to protect potentially sensitive data.
If you enable it, you can configure in detail what parts of the request and response should be logged.
You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging.

The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields.

{language_0 == "python" && <p>Check out the <a href="/sdk-reference/python/configuration">SDK reference</a> to learn more about the request logging configuration options.</p>}

{language_0 == "javascript" && <p>Check out the <a href="/sdk-reference/javascript/configuration">SDK reference</a> to learn more about the request logging configuration options.</p>}

{language_0 == "go" && <p>Check out the <a href="/sdk-reference/go/configuration">SDK reference</a> to learn more about the request logging configuration options.</p>}

<CodeGroup>
  ```go Basic example theme={null}
  package main

  import (
      apitally "github.com/apitally/apitally-go/echo-v5"
      "github.com/labstack/echo/v5"
  )

  func main() {
      e := echo.New()

      config := apitally.NewConfig("your-client-id")
      config.Env = "dev" // or "prod" etc.
      config.RequestLogging.Enabled = true
      config.RequestLogging.LogRequestHeaders = true
      config.RequestLogging.LogRequestBody = true
      config.RequestLogging.LogResponseBody = true
      config.RequestLogging.CaptureLogs = true
      config.RequestLogging.CaptureTraces = false // requires instrumentation

      e.Use(apitally.Middleware(e, config))

      // ... rest of your code ...
  }
  ```

  ```go Advanced example theme={null}
  package main

  import (
      "regexp"
      "strings"

      apitally "github.com/apitally/apitally-go/echo-v5"
      "github.com/labstack/echo/v5"
  )

  func main() {
      e := echo.New()

      config := apitally.NewConfig("your-client-id")
      config.Env = "dev" // or "prod" etc.
      config.RequestLogging.Enabled = true
      config.RequestLogging.LogQueryParams = true
      config.RequestLogging.LogRequestHeaders = true
      config.RequestLogging.LogRequestBody = true
      config.RequestLogging.LogResponseHeaders = true
      config.RequestLogging.LogResponseBody = true
      config.RequestLogging.LogPanic = true
      config.RequestLogging.CaptureLogs = true
      config.RequestLogging.CaptureTraces = false // requires instrumentation
      // Mask query parameters using regex
      config.RequestLogging.MaskQueryParams = []*regexp.Regexp{regexp.MustCompile(`^card_number$`)}
      // Mask headers using regex
      config.RequestLogging.MaskHeaders = []*regexp.Regexp{regexp.MustCompile(`^X-Sensitive-Header$`)}
      // Mask request/response body fields using regex
      config.RequestLogging.MaskBodyFields = []*regexp.Regexp{regexp.MustCompile(`^sensitive_field$`)}
      // Exclude paths from request logging using regex (common health check paths are excluded by default)
      config.RequestLogging.ExcludePaths = []*regexp.Regexp{regexp.MustCompile(`/metrics$`)}
      // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints)
      // The callback should return nil to mask the whole body, or return the (modified) raw body
      config.RequestLogging.MaskRequestBodyCallback = func(request *apitally.Request) []byte {
          if strings.HasPrefix(request.Path, "/admin/") {
              return nil // Mask the whole body for admin endpoints
          }
          return request.Body
      }
      config.RequestLogging.MaskResponseBodyCallback = func(request *apitally.Request, response *apitally.Response) []byte {
          if strings.HasPrefix(request.Path, "/admin/") {
              return nil // Mask the whole body for admin endpoints
          }
          return response.Body
      }
      // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer)
      // The callback should return true to exclude the request
      config.RequestLogging.ExcludeCallback = func(request *apitally.Request, response *apitally.Response) bool {
          return request.Consumer == "some-consumer"
      }

      e.Use(apitally.Middleware(e, config))

      // ... rest of your code ...
  }
  ```
</CodeGroup>

<Check>
  The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail.
</Check>

## Enable tracing

Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations.

To enable tracing, set `CaptureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/go/tracing) for further instructions.
