---
title: "Tutorial | Speedscale Docs"
description: "Install Speedscale and learn how to capture, transform, and replay traffic with mocks using the example app in this comprehensive tutorial."
canonical: "https://docs.speedscale.com/tutorial/"
---

[Documentation index](https://docs.speedscale.com/tutorial/llms.txt) | [Markdown](https://docs.speedscale.com/tutorial/index.md) | [Canonical page](https://docs.speedscale.com/tutorial/)

# Tutorial

Security-first setup options

*   **Local-first recording:** use `proxymock` for desktop workflows when you want captured traffic to stay local by default.
*   **Enterprise boundary control:** use [Bring Your Own Cloud (BYOC)](https://docs.speedscale.com/byoc/) when you need customer-controlled cloud isolation.
*   **Sensitive data controls:** enable [DLP](https://docs.speedscale.com/guides/dlp/) so sensitive fields are redacted before data leaves your network.

In this guide we're going to use [this repo's](https://github.com/speedscale/demo) example app in the `java` directory to [capture](https://docs.speedscale.com/concepts/capture/), [transform](https://docs.speedscale.com/concepts/transforms/) and [replay](https://docs.speedscale.com/concepts/replay/) traffic with [mocks](https://docs.speedscale.com/concepts/service_mocking/).

<a id="prerequisites"></a>

## Prerequisites

1.  [speedctl CLI is installed](https://docs.speedscale.com/getting-started/installation/install/cli/)
2.  [proxymock CLI is installed](https://docs.speedscale.com/proxymock/getting-started/installation/)
3.  After initializing proxymock, `SPEEDSCALE_HOME` should be set correctly. If it is missing, run `proxymock init` again and allow it to update your rcfile.
4.  Clone the repo: [https://github.com/speedscale/demo](https://github.com/speedscale/demo)
5.  [Java](https://jdk.java.net/) is present and `JAVA_HOME` is set correctly (on MacOS you can run `/usr/libexec/java_home` to find the correct `JAVA_HOME`)
6.  Install `jq` and `make` if not already on your desktop (`brew install jq` and `brew install make` on MacOS for example)

<a id="the-app"></a>

## The App

The app is a Java Spring Boot web server with authenticated endpoints that makes requests out to a few external services. The project README (at `java/README.md`) shows ways to run the app locally, in Docker and in Kubernetes. Speedscale can be configured to be compatible with whichever way you choose to deploy the app. Note that for this test run we'll disable DLP for simplicity, but production workflows should enable DLP before sending captured traffic outside your environment.

<a id="capture"></a>

## Capture

Make sure you navigate to the `java` subdirectory within the `demo` repository.

**Kubernetes**

1.  [Install the operator](https://docs.speedscale.com/getting-started/installation/install/kubernetes-operator/)
2.  Recommended: enable the [eBPF collector](https://docs.speedscale.com/reference/ebpf-traffic-collection/) to capture traffic without proxies or app changes. Follow the Helm-based setup to target the demo namespace/workload.
    *   Fallback: if eBPF is not suitable in your cluster, deploy the demo app with the Speedscale sidecar by running:

```bash
make kube-capture
```

3.  Validate the app was deployed properly with:

```bash
kubectl -n default get pods
```

Depending on your chosen capture method you may see either `1/1` (eBPF collector) or `2/2` (application + sidecar) for the `java-server` pod.

```bash
NAME                           READY   STATUS    RESTARTS   AGE
java-client-54ccddd5cd-tthld   1/1     Running   0          37s
java-server-597577977-bthvl    2/2     Running   0          37s
```

This should start generating traffic that you can see in the Speedscale UI within a couple of minutes.

**Docker**

1.  Generate a jks for the Java app:

```bash
docker run --rm -v ~/.speedscale/certs:/speedscale openjdk bash -c 'keytool -importcert -noprompt -cacerts  -storepass changeit  -alias speedscale -file  /speedscale/tls.crt && cp ${JAVA_HOME}/lib/security/cacerts /speedscale/cacerts.jks'
```

2.  Run:

```bash
speedctl install
```

Choose the `Docker` option and then the `Capture` option (option 1). You can name the service anything you want, the default port setting of `8080` is necessary.

3.  Run the following to bring up the Speedscale capture components:

```bash
docker compose --file speedscale-docker-capture.yaml up -d
```

4.  Run in your current terminal window:

```bash
make compose-capture
```

5.  Open a new terminal window and run:

```bash
make client-capture
```

This should start generating traffic that you can see in the Speedscale UI within a couple of minutes.

**Local**

1.  Generate local certs by running the following command (it should say "Certificate was added to keystore"):

```bash
proxymock admin certs --jks
```

2.  Start the capture system with this command:

```bash
proxymock record --app-port 8080
```

3.  Open another terminal window to run the `java-server` program:

```bash
make local-capture
```

4.  Open a third terminal window to run the client application:

```bash
make client-capture
```

5.  This will generate traffic, and you can browse the traffic in your browser with this command:

```bash
proxymock web --in proxymock/recorded-YOUR_TIMESTAMP
```

6.  If you want to push this data to Speedscale cloud you can with the command:

```bash
proxymock cloud push snapshot --in proxymock/recorded-YOUR_TIMESTAMP
```

<a id="analyze"></a>

## Analyze

After a few minutes you should be able to see your traffic in the [Speedscale dashboard](https://app.speedscale.com/). Make sure to select the the same service name that you entered in `speedctl install` from the traffic dropdown. You should be able to see the inbound and outbound calls for this app as shown below.

![Traffic](https://docs.speedscale.com/assets/images/traffic-30f6cfdc027fa0ce2bfc2ca8224c2d18.png)

You can also drill down into specific requests-response pairs (RRPairs). For eg. we see the request we make to our app to get the max interest rate for treasuries.

![Server](https://docs.speedscale.com/assets/images/server-request-ca3cd79f3e0e5e4a8cc8e1753c763f79.png)

And we can also see the outbound request our app makes to the Treasury API to fulfill this request.

![Treasury](https://docs.speedscale.com/assets/images/out-request-96981a723fd676d03d9b68bc3ed76973.png)

You can and inspect it further or you can skip ahead to running a replay which will also create a snapshot as a side effect.

<a id="replay"></a>

## Replay

We're now going to run a replay for this captured traffic.

**Kubernetes**

Click the `Replay as Tests/Mocks` button on the top right and walk through the wizard. All the default settings are ok here. You can also do this outside of the UI with more instructions [here](https://docs.speedscale.com/guides/replay/kube/).

**Docker**

1.  Click the `Save to Tests/Mocks` button in the top right. All the default settings are ok here. You can find more detailed instructions in the [Create a Snapshot](https://docs.speedscale.com/guides/creating-a-snapshot/) section.
2.  Once you see the Snapshot summary, copy the snapshot ID from the URL or by clicking the `Copy Snapshot ID` option from the three dot menu.
3.  Run:

```bash
speedctl install
```

Choose the `Docker` option and then `Replay` (option 3).

4.  Select your service and the standard test config. Make sure you select the same service name you entered during the capture phase.
5.  Input the Snapshot ID from step 1, the port should still be `8080`
6.  Run in one terminal window:

```bash
make compose-replay
```

7.  Run in another window to start the replay:

```bash
export TEST_REPORT_ID=$(uuidgen |  tr '[:upper:]' '[:lower:]'); docker compose --file speedscale-docker-replay.yaml up -d && echo "Your test report can be found at: https://app.speedscale.com/reports/${TEST_REPORT_ID}"
```

**Local**

1.  Click the `Save to Tests/Mocks` button in the top right. All the default settings are ok here. You can find more detailed instructions in the [Create a Snapshot](https://docs.speedscale.com/guides/creating-a-snapshot/) section.
2.  Once you see the Snapshot summary, copy the snapshot ID from the URL or by clicking the `Copy Snapshot ID` option from the three dot menu.
3.  This is how you run the application:

```bash
make local-replay
```

4.  In another terminal window, download the modified snapshot locally with:

```bash
proxymock cloud pull snapshot SNAPSHOT_ID
```

5.  Now you can run the mock server like so:

```bash
proxymock mock --in proxymock/snapshot-SNAPSHOT_ID
```

6.  In a third terminal window, you can run the test replay:

```bash
proxymock replay --in proxymock/snapshot-SNAPSHOT_ID
```

<a id="making-sense-of-a-replay"></a>

## Making sense of a Replay

If you are already viewing the Snapshot you recorded, you can see your replay appear in the `Replay` tab. Alternatively, you can find a report for your Replay in the [dashboard](https://app.speedscale.com/reports). It should look something like this.

![Report](https://docs.speedscale.com/assets/images/report-78153bb85ce80a861157ecc0a7b8aac5.png)

We can see that all the requests our app makes to third party APIs were mocked out with 100% accuracy. For eg. we can see the request our app made to the Treasury API that was actually mocked out which is great for isolation during tests but we can also do this for other parts of our development cycle as detailed [here](https://docs.speedscale.com/guides/replay/mocks/#responder-only).

![Responder](https://docs.speedscale.com/assets/images/mocks-b8167f5129e651a1c497fbf9d5903702.png)

You can also see that the accuracy isn't 100%. We can drill down into a specific assertion to see why.

![JWT](https://docs.speedscale.com/assets/images/jwt-22dbd37ac4575d44492e0cae4a8803f8.png)

<a id="transform"></a>

### Transform

The JWT we get from the login request is different which is expected. If we were replaying in a different environment, we might need different credentials entirely for the login request. Another pattern might be a set of traffic where we don't have a login request and instead we need to [resign the JWT](https://docs.speedscale.com/guides/replay/resign-jwt/) from our captured traffic. This is where [Transforms](https://docs.speedscale.com/concepts/transforms/) come into play and we can edit our captured data to parameterize parts of it. As an example, we can transform our snapshot to edit the password.

Find the request on the snapshot's **Traffic** tab and open **Request**, then click the pencil icon next to the field you want to edit, which in our case is the password. Choose **Modify**.

![The pencil menu on the password field of a login request, with Modify password](https://docs.speedscale.com/assets/images/login-transform-6cee4daf031f1ce4a975e36bb812fe6d.png)

This opens the transform chain on the **Prepare** tab. Select **Add step** and pick a transform.

![The transform picker in the chain, with Constant selected](https://docs.speedscale.com/assets/images/login-transform-modal-3333ef609c72058c1ca1665421b38ca3.png)

For now we'll just replace it with a constant but there are all sorts of options that can be chained together. **Replay uses** shows what the replay will send. Select **Save and reanalyze** to keep the change.

![The finished chain, where the password becomes a constant and Replay uses shows the new request body](https://docs.speedscale.com/assets/images/login-new-eeccb26fbd1a72439c956882deab3ffb.png)

We just did a transform for the traffic coming into our app during a replay. We can also use transforms for mocks in case we have to parameterize fields like session ids, dates, etc. Check out [this guide](https://docs.speedscale.com/guides/replay/mocks/edit-sig/) for a deep dive.

<a id="assertions"></a>

### Assertions

Another assertion that failed in our report is for the `/spacex/ship` endpoint.

![Ship Endpoint](https://docs.speedscale.com/assets/images/random-ce4e5d14df756665f41926d6500b67f4.png)

Our app returns a different ship ID every time we make a request so this is an expected failure. We can edit the test config for our Report to account for this.

![Edit Test Config](https://docs.speedscale.com/assets/images/report-tc-b5b44cfc80fa9a3c4761698398198cef.png)

Click the pencil next to the `HTTP Response Body` assertion and we can add `ship_id` as a json path to ignore.

![Edited](https://docs.speedscale.com/assets/images/report-ignore-5c429de3365e1511e2dd464a48b71ee3.png)

After saving, we can reanalyze the report and we see much better results!

![Success](https://docs.speedscale.com/assets/images/report-success-33d2821d6f13d99c6db2bc0a86029efd.png)

<a id="overview"></a>

## Overview

In this demo we:

1.  Captured some traffic
2.  Analyzed it in the Traffic Viewer
3.  Optionally configured DLP
4.  Ran a replay and created a snapshot
5.  Used auto generated mocks during the replay
6.  Transformed some snapshot traffic
7.  Edited the assertions
8.  Reanalyzed the report for a higher accuracy

# Next Steps

This is just a small subset of things you can do with Speedscale, other things to try out could be:

1.  Capture traffic from one of your own apps
2.  [Replay traffic from one cluster into another](https://docs.speedscale.com/guides/replay/guide_other_cluster/)
3.  [Run a load test](https://docs.speedscale.com/guides/replay/load-test/)
4.  [Integrate with CI/CD](https://docs.speedscale.com/guides/integrations/cicd/)

<a id="uninstall"></a>

## Uninstall

If you'd like to remove the demo from your environment follow these instructions:

**Kubernetes**

```bash
make kube-clean
```

**Docker**

```bash
docker compose -f speedscale-docker-capture.yaml down
```

<a id="optional-data-loss-protection"></a>

### (Optional) Data loss Protection

If we drill down into a request, we can also see data we may not want to leave our environment.

![Auth](https://docs.speedscale.com/assets/images/unredacted-1425a751a57ec11655fb677914ce7b7e.png)

You can enable DLP to redact certain fields from an RRPair at capture time. Note that this will cause your replays to have low accuracies because necessary information will be masked. Check out the [dlp](https://docs.speedscale.com/guides/dlp/) section for more information on DLP configuration. As a starter, you can follow the instructions below.

**Kubernetes**

Run:

```bash
speedctl infra dlp enable
```

**Docker**

Edit `speedscale-docker-capture.yaml` to add the following two environment variables.

```yaml
services:
  forwarder:
    environment:
      - SPEEDSCALE_REDACT=true
      - SPEEDSCALE_DLP_CONFIG=standard
```

**Local**

When running `proxymock` the files are stored locally but don't run through data loss prevention.

Now we see the authorization header is redacted and never makes it to Speedscale.

![Redacted](https://docs.speedscale.com/assets/images/redacted-69e950e4a6412e33397f5a80803a8fc1.png)

For more complex DLP configuration you can use [this guide](https://docs.speedscale.com/guides/dlp/).
