Skip to content

uproot

uproot is a modern, open-source framework for developing and conducting browser-based behavioral experiments. Build studies with hundreds of participants, from simple surveys to complex real-time multiplayer games.

  Try the live demo

Source code: github.com/mrpg/uproot
Examples: github.com/mrpg/uproot-examples

Work in progress

uproot is in initial development. Breaking changes may occur between releases. The announce­ments shown in the admin interface will tell you when action is needed.

  • Get started in minutes


    Install uproot with a single command and create your first experiment.

    Installation

  • Learn by doing


    Follow the tutorial to build a complete prisoner’s dilemma experiment.

    Tutorial

  • Built for multiplayer


    Group participants, synchronize progress, and enable real-time interaction.

    Multiplayer experiments

  • Explore examples


    Ready-to-use experiments covering common paradigms and techniques.

    Example apps

  • AI-assisted development


    Build experiments faster with Claude Code, Codex, and other agentic coding tools.

    Set up AI tooling

Why uproot?

  • Reproducible experiments: Your project folder plus uv recreates the exact software environment of your study, years later.
  • Real-time multiplayer: Built-in support for grouping participants, synchronization, and live interactions.
  • Flexible data storage: Append-only log ensures data persistence and supports arbitrary data types.
  • Modern stack: Built on FastAPI for performance and reliability.
  • 100% open source: LGPL-licensed with no vendor lock-in.

The full case for uproot

Quick example

Here is the complete Python code of a two-player prisoner’s dilemma:

from uproot.fields import *
from uproot.smithereens import *

DESCRIPTION = "Prisoner's dilemma"
SUGGESTED_MULTIPLE = 2


class C:
    PAYOFF_MATRIX = {
        # (you cooperate, other cooperates): your payoff
        (True, True): 10,
        (True, False): 0,
        (False, True): 15,
        (False, False): 3,
    }


class Instructions(Page):
    pass


class GroupPlease(GroupCreatingWait):
    group_size = 2


class Dilemma(Page):
    fields = dict(
        cooperate=RadioField(
            label="Do you wish to cooperate?",
            choices=[(True, "Yes"), (False, "No")],
        ),
    )


class Sync(SynchronizingWait):
    @classmethod
    def all_here(page, group: GroupType) -> None:
        for player in group.players:
            player.payoff = C.PAYOFF_MATRIX[
                player.cooperate,
                player.other_in_group.cooperate,
            ]


class Results(Page):
    pass


page_order = [
    Instructions,
    GroupPlease,
    Dilemma,
    Sync,
    Results,
]

Browse the complete example including HTML templates

Getting in touch

uproot is developed by Max Grossmann and Holger Gerhardt. Click here for more information.