Apps & rounds¶
An oTree app is a folder containing Python and HTML code. A project contains multiple apps. A session is basically a sequence of apps that are played one after the other.
Creating an app¶
If you’re using oTree Studio, click “Apps”.
If you’re using PyCharm, enter
otree startapp your_app_name
at the command line.
You can make a game run for multiple rounds by setting
For example, if your session config’s
num_rounds = 3 and
num_rounds = 1,
then your sessions will contain 4 subsessions.
You can get the current round number with
(this attribute is present on subsession, group, player, and page objects).
Round numbers start from 1.
Passing data between rounds or apps¶
Each round has separate
For example, let’s say you set
self.player.my_field = True in round 1.
In round 2, if you try to access
you will find its value is
This is because the
in round 1 are separate from
Player objects in round 2.
To access data from a previous round or app, you can use one of the techniques described below.
in_rounds, in_previous_rounds, in_round, etc.¶
Player, group, and subsession objects have the following methods:
For example, if you are in the last round of a 10-round game,
player.in_previous_rounds() will return a list with 9 player objects,
which represent the current participant in all previous rounds.
player.in_all_rounds() is almost the same but the list will have 10 objects,
because it includes the current round’s player.
player.in_rounds(m, n) returns a list of players representing the same participant from rounds
player.in_round(m) returns just the player in round
For example, to get the player’s payoff in the previous round,
you would do
self.player.in_round(self.round_number - 1).payoff.
These methods work the same way for subsessions (e.g.
They also work the same way for groups, but it does not make sense to use them if you re-shuffle groups between rounds.
If you want to access a participant’s data from a previous app,
you should store this data on the participant object,
which persists across apps (see Participant).
in_all_rounds() only is useful when you need to access data from a previous
round of the same app.)
Put it in
participant.vars, which is a dictionary that can store any data.
For example, you can set an attribute like this:
self.participant.vars['blah'] = [1, 2, 3]
Later in the session (e.g. in a separate app), you can retrieve it like this:
# the below line gives [1, 2, 3] self.participant.vars['blah'] # or try printing: print('vars is', self.participant.vars)
As described here, the current participant can be
accessed from a
class MyPage(Page): def before_next_page(self): self.participant.vars['foo'] = 1
class Player(BasePlayer): def some_method(self): self.participant.vars['foo'] = 1
You can also access it from
Subsession, as long as you retrieve
Player instance (e.g. using
class Subsession(BaseSubsession): def creating_session(self): for p in self.get_players(): p.participant.vars['foo'] = 1
You can test if
'my_var' exists with
if 'my_var' in self.participant.vars:.
participant.vars is not included in the Excel/CSV data export,
or in the “Data” tab in the session admin. If you want that, you can create a
StringField on your player (for example, called
and then at the end of your session, assign:
self.player.participant_vars_dump = str(self.participant.vars)
(The same concept applies for
For global variables that are the same for all participants in the session,
you can use
This is a dictionary just like
participant.vars. The difference is that
if you set a variable in
self.session.vars, it will apply
to all participants in the session, not just one.
As described here, the
session object can be
accessed from a
Page object or any of the models (