Introducing ReduxVCR

The adorable tool that lets you record and re-watch user sessions.

Joshua Comeau
5 min readOct 13, 2016

--

A few weeks ago, I was working on a Web Audio synthesizer called Key&Pad.

It struck me, while I was building it, that I wouldn’t be able to hear the interesting/beautiful/zany sounds that users made with it. What good is making a fun toy app if you can’t see (hear) what people do with it!

Because that project used Redux, though, the solution was obvious: Since every user action was already passing through the store, I just needed some middleware to capture it and track the time between each action. Then, I could just “replay” those actions in realtime.

As it turns out, there were a fair amount of problems that I hadn’t anticipated, and solving them in a generic way has been challenging. This tool is still in early alpha, and there’s a lot that has yet to be solved, but I’ve been using it in production without issue. I figure it’s time to have others start to poke and play with it :)

The Results

Here are some of my favourite recorded sessions so far:
(give the cassettes a second or two to load)

  • Noisecore
    A bunch of really neat, really dissonant sounds using bass notes, distortion, and a myriad of other effects.
  • Gradual Experimentation
    This user makes some interesting noises with chorus. Mostly I like this session because the experimentation and discovery process is so evident.
  • Absolutely beautiful
    A lovely melody that becomes captivating with stereo tremolo. Evolves into a wub-wub dubstep bass.

Remixable

Redux VCR doesn’t mind being interrupted; it’ll keep carrying out its sequence of actions, without complaining if you jam along with it.

I’ve been having a blast playing notes or tweaking effects on recorded sessions. Here’s a simple session you can have fun with; try playing some notes over it, or changing the effects!

Read on to learn more about how it works, how to get started, and where the project is going, or jump straight to the project on GitHub.

How It Works

Redux VCR is built to be modular. It consists of 4 main parts. Each of these pieces operate with Cassettes, plain objects that hold the sequence of actions needed to recreate a user’s session, as well as some metadata.

Capture

Capture is responsible for observing the stream of Redux actions, and selecting the ones it wants to record.

It’s pretty flexible: You can blacklist certain actions that you don’t want to record, or provide a “start action” that will kick off the recording (if, say, you don’t want to bother recording the onboarding process).

It creates a Cassette object, keeps track of how much time has elapsed between actions, and passes it on to the next module when stuff happens.

Persist

Persist is responsible for, well, persistence. The default module uses Firebase, and it will update the remote copy of the Cassette whenever it’s handed an updated version.

It can be debounced, to avoid spamming the server.

Retrieve

Retrieve is the inverse of Persist; it’s responsible for securely fetching the Cassettes. The default module uses Firebase as well.

Unlike the previous two modules, you likely don’t want to ship Retrieve in production. It’s used exclusively in development, so that you and you alone can re-watch user sessions.

Replay

Finally, Replay is the cute little VCR UI that lets you select and control cassettes. It offers the ability to modify the playback speed of actions, and I hope to add a scrubber that will let you jump to specific parts of the sequence.

It also consists of a middleware that allows us to pass custom options. For example, we can specify a max wait time between actions, to trim out long gaps where users are idle.

It also uses a higher-order reducer, to update the state when cassettes are loaded and ejected.

Similar to Retrieve, this is a production-only module.

Serverless Security

A concern with the development of this project was to ensure that users’ sessions were kept secure. At the same time, I didn’t want to enforce any kind of back-end. Key&Pad lives on GitHub Pages with no server-side logic.

Firebase provides a nice solution, with its custom Rules API.

When your application loads, all users are automatically authenticated using Anonymous Authentication. Essentially this just gives them a unique ID that persists for the session.

Regular users are not able to read from the database at all, and they’re only allowed to write to their custom slice of the database, using their unique ID as the key.

For admins, I’m using GitHub OAuth. You specify, in the Firebase Rules, that read access is only given to users who match a specific GitHub account, and then authenticate by clicking the VCR and signing into GitHub.

Getting Set Up

Every project is different, and I’ve tried to make the setup as straightforward as possible while allowing for various configurations.

A full guide can be found on GitHub, but I think an easier way to grok the high-level concepts is to look at some examples.

I’ve created a repo, redux-vcr-todomvc, which installs Redux VCR in a few different ways. Each is a non-merged Pull Request, so you can view the diffs required to integrate Redux VCR into TodoMVC:

  • Quickstart
    This is the easiest way to get started, but it’s not recommended for production usage.
  • Production-Ready
    This version takes care to keep admin-only modules out of the production build.
  • With an Initial Cassette
    Auto-load a specific cassette, specified by a query parameter. This is useful for favouriting a specific cassette, but can also be used to load the last-played cassette from localStorage.
  • More to come!

Beyond the setup in the code, some setup is required with Firebase as well. Check out the Firebase Config docs to see how that works.

Help Build Something Cool

This project is really early, and there’s much work to be done. I have limited time to dedicate to this project, and I’m looking for contributors! I have huge ambitions for this tool, but I can’t do it all alone.

As it stands, Redux VCR works great for simple toy apps, like my synthesizer, but it isn’t sophisticated enough yet to handle most use-cases.

Some stuff I’d like to add:

  • A way of stubbing out server requests. We likely don’t want to send real API requests when replaying sessions.
  • Native window-level event-capturing like mousemoves and scrolls.
  • A proper web interface for managing recorded cassettes.
  • A scrubber for being able to “skip to” sections of the tape, quickly replay certain sections, etc.

Contributors who open a significant, acceptable PR will be given full collaborator rights. I want this project to be yours as much as mine. For the community, by the community.

--

--