Skip to main content
Match options control every aspect of your CS2 match, from basic settings like match type to advanced configurations like timeout permissions. This guide details all available options.

Basic Settings

Match Type

Select the competitive format:
e_match_types_enum.Competitive  // Standard 5v5 competitive
e_match_types_enum.Wingman       // 2v2 wingman format
e_match_types_enum.Custom        // Custom format
Standard 5v5 competitive format:
  • 5 players per team
  • MR12 default (12 rounds per half)
  • Full economy system
  • Active Duty map pool

Best Of Format

Number of maps to play:
const bestOfOptions = [1, 3, 5].map((rounds) => ({
  value: rounds.toString(),
  display: `Best of ${rounds}`,
}));
The best-of value determines the veto process and match length. BO1 uses simplified veto, while BO3 and BO5 use full pick/ban sequences.

Map Configuration

Map Veto

Enable structured map selection:
<FormField v-slot="{ value, handleChange }" name="map_veto">
  <FormItem>
    <Card class="cursor-pointer" @click="handleChange(!value)">
      <div class="flex justify-between items-center">
        <FormLabel>Map Veto Settings</FormLabel>
        <Switch :model-value="value" />
      </div>
      <FormDescription>
        Teams alternate picking and banning maps until the required
        number is selected
      </FormDescription>
    </Card>
  </FormItem>
</FormField>
Disabled: Direct map selection
Enabled: Teams follow veto protocol

Map Pool Selection

// Use Valve's official competitive map pool
match.options.custom_map_pool = false;
match.options.map_pool_id = defaultMapPoolId;

Map Pool Logic

The form automatically adjusts map pools based on settings:
watch: {
  ['form.values.type']: {
    handler(type) {
      // Reset map pool when type changes
      this.form.setFieldValue('map_pool', []);
      if (this.form.values.map_veto) {
        this.form.setFieldValue('map_pool_id', this.defaultMapPool.id);
      }
    },
  },
  ['form.values.map_veto']: {
    handler(mapVeto) {
      if (mapVeto) {
        this.form.setFieldValue('custom_map_pool', false);
      } else {
        this.form.setFieldValue('custom_map_pool', true);
      }
    },
  },
}
For non-veto matches with best-of > 1, the system limits map selection to the best-of value.

Game Settings

Max Rounds (MR)

Rounds per half before overtime:
<FormField v-slot="{ componentField }" name="mr">
  <FormItem>
    <FormLabel>Max Rounds</FormLabel>
    <FormDescription>
      Number of rounds per half (MR8, MR12, MR15)
    </FormDescription>
    <Select v-bind="componentField">
      <SelectContent>
        <SelectItem value="8">8</SelectItem>
        <SelectItem value="12">12</SelectItem>
        <SelectItem value="15">15</SelectItem>
      </SelectContent>
    </Select>
  </FormItem>
</FormField>
  • MR8: Wingman matches, shorter competitive games
  • MR12: Standard competitive (Valve default)
  • MR15: Legacy competitive format (pre-CS2)

Overtime

Enable overtime rounds:
<FormField v-slot="{ value, handleChange }" name="overtime">
  <FormItem>
    <div class="flex flex-row items-center justify-between">
      <div>
        <FormLabel>Overtime</FormLabel>
        <FormDescription>
          Enable overtime periods if score is tied
        </FormDescription>
      </div>
      <Switch :model-value="value" @update:model-value="handleChange" />
    </div>
  </FormItem>
</FormField>
When enabled:
  • MR3 overtime periods (6 rounds total)
  • Economy reset each overtime
  • Repeat until winner determined

Knife Round

Starting side selection via knife round:
<FormField v-slot="{ value, handleChange }" name="knife_round">
  <FormItem>
    <div class="flex flex-row items-center justify-between">
      <div>
        <FormLabel>Knife Round</FormLabel>
        <FormDescription>
          Winner chooses starting side (CT or T)
        </FormDescription>
      </div>
      <Switch :model-value="value" @update:model-value="handleChange" />
    </div>
  </FormItem>
</FormField>
Knife rounds occur before each map. The winning team decides which side to start on.

Region Settings

Single Region

Select one server region:
<Select v-model="select_single_region">
  <SelectContent>
    <SelectItem
      v-for="region in regions"
      :value="region.value"
    >
      {{ region.description }}
    </SelectItem>
  </SelectContent>
</Select>

Region Veto

Enable region selection process:
<FormField v-slot="{ value, handleChange }" name="region_veto">
  <FormItem>
    <Card @click="handleChange(!value)">
      <div class="flex justify-between items-center">
        <FormLabel>Region Veto</FormLabel>
        <Switch 
          :model-value="value" 
          :disabled="form.values.lan"
        />
      </div>
      <FormDescription>
        Teams alternate vetoing regions until one remains
      </FormDescription>
    </Card>
  </FormItem>
</FormField>
With region veto:
  • Select multiple preferred regions
  • Teams ban regions alternately
  • Final region hosts the server
// Region veto enabled
match.options.region_veto = true;
match.options.regions = ['us-east', 'us-west', 'eu-west'];

// Single region
match.options.region_veto = false;
match.options.regions = ['us-east'];

LAN Mode

For LAN tournaments:
<div class="flex items-center gap-4">
  <span>LAN Match</span>
  <Switch
    :model-value="form.values.lan"
    @update:model-value="(checked) => form.setFieldValue('lan', checked)"
  />
</div>
LAN mode disables region veto and uses LAN-optimized server settings.

Player Settings

Substitutes

Allow additional players beyond starting lineup:
<FormField v-slot="{ value }" name="number_of_substitutes">
  <FormItem>
    <FormLabel>Number of Substitutes</FormLabel>
    <FormDescription>
      Substitutes can be swapped in during pauses (0-5)
    </FormDescription>
    <NumberField
      :min="0"
      :max="5"
      :model-value="value"
      @update:model-value="(val) => form.setFieldValue('number_of_substitutes', val)"
    >
      <NumberFieldContent>
        <NumberFieldDecrement />
        <NumberFieldInput />
        <NumberFieldIncrement />
      </NumberFieldContent>
    </NumberField>
  </FormItem>
</FormField>

Coaches

Coach functionality requires server plugin support. Not available on all servers.

Broadcast Settings

TV Delay

GOTV spectator delay:
<FormField v-slot="{ value }" name="tv_delay">
  <FormItem>
    <FormLabel>TV Delay</FormLabel>
    <NumberField
      :min="0"
      :max="120"
      :model-value="value"
    >
      <NumberFieldContent>
        <NumberFieldDecrement />
        <NumberFieldInput />
        <NumberFieldIncrement />
      </NumberFieldContent>
    </NumberField>
    <FormDescription>
      Delay in seconds (0-120) for GOTV spectators
    </FormDescription>
  </FormItem>
</FormField>
Purpose:
  • Prevent stream sniping
  • Protect team strategies
  • Standard: 90 seconds for competitive matches

Match Flow Settings

Check-in Settings

Who must check in before match:
const checkInSettings = [
  {
    value: e_check_in_settings_enum.Admin,
    display: 'Admins Only',
  },
  {
    value: e_check_in_settings_enum.Captains,
    display: 'Team Captains',
  },
  {
    value: e_check_in_settings_enum.Players,
    display: 'All Players',
  },
];

Ready Settings

Who can ready up the team:
const readySettings = [
  {
    value: e_ready_settings_enum.Admin,
    display: 'Admins Only',
  },
  {
    value: e_ready_settings_enum.Captains,
    display: 'Team Captains',
  },
  {
    value: e_ready_settings_enum.Coach,
    display: 'Coaches',
  },
  {
    value: e_ready_settings_enum.Players,
    display: 'All Players',
  },
];

Auto-Cancellation

Prevent abandoned matches:
<FormField v-slot="{ value, handleChange }" name="auto_cancellation">
  <FormItem>
    <div class="flex justify-between">
      <div>
        <FormLabel>Auto Cancellation</FormLabel>
        <FormDescription>
          Automatically cancel if players don't check in or match stalls
        </FormDescription>
      </div>
      <Switch :model-value="value" @update:model-value="handleChange" />
    </div>

    <div v-if="value" class="space-y-4">
      <FormField name="auto_cancel_duration">
        <FormLabel>Check-in Timeout (minutes)</FormLabel>
        <Input type="number" min="1" />
      </FormField>

      <FormField name="live_match_timeout">
        <FormLabel>Live Match Timeout (minutes)</FormLabel>
        <Input type="number" min="1" />
      </FormField>
    </div>
  </FormItem>
</FormField>

Timeout Settings

Tactical Timeouts

Who can call tactical timeouts:
const timeoutSettings = [
  { value: e_timeout_settings_enum.Admin, display: 'Admins' },
  { value: e_timeout_settings_enum.Coach, display: 'Coaches' },
  { value: e_timeout_settings_enum.CoachAndCaptains, display: 'Coaches & Captains' },
  { value: e_timeout_settings_enum.CoachAndPlayers, display: 'Everyone' },
];

Technical Timeouts

Separate permissions for technical issues:
<FormField name="tech_timeout_setting">
  <FormLabel>Technical Timeout Permissions</FormLabel>
  <FormDescription>
    Who can call technical timeouts for issues
  </FormDescription>
  <Select>
    <SelectContent>
      <SelectItem v-for="setting in timeoutSettings" :value="setting.value">
        {{ setting.display }}
      </SelectItem>
    </SelectContent>
  </Select>
</FormField>

Advanced Options

Match Mode

Control match progression:
const matchModeSettings = [
  {
    value: e_match_mode_enum.auto,
    display: 'Auto',
    description: 'Match progresses automatically',
  },
  {
    value: e_match_mode_enum.admin,
    display: 'Admin Controlled',
    description: 'Admin must manually progress match',
  },
];
Recommended for most matches:
  • Server automatically goes live when ready
  • Knife round proceeds automatically
  • Maps start without manual intervention

Default Models

Force default player models:
<FormField v-slot="{ value, handleChange }" name="default_models">
  <Card class="cursor-pointer" @click="handleChange(!value)">
    <div class="flex justify-between items-center">
      <FormLabel>Default Models</FormLabel>
      <Switch :model-value="value" />
    </div>
    <FormDescription>
      Force default player models (disables agent skins)
    </FormDescription>
  </Card>
</FormField>
Enabling default models may improve competitive integrity by ensuring consistent player visibility.

Lobby Access

Control who can join the match:
e_lobby_access_enum.Open     // Anyone can join
e_lobby_access_enum.Friends  // Steam friends only
e_lobby_access_enum.Invite   // Invite code required
e_lobby_access_enum.Private  // Manual addition only
See Match Lobbies for detailed lobby access information.

Options Validation

The form validates all options:
import matchOptionsValidator from '~/utilities/match-options-validator';

const form = useForm({
  validationSchema: toTypedSchema(
    matchOptionsValidator(
      this,
      {
        pug: z.boolean().default(true),
        team_1: z.string().optional(),
        team_2: z.string().optional(),
      },
      useApplicationSettingsStore().settings,
    ),
  ),
});

Saving Options

Options are saved via GraphQL mutation:
await this.$apollo.mutate({
  variables: setupOptionsVariables(form, {
    mapPoolId: mapPoolId,
    matchOptionsId: this.match.options.id,
  }),
  mutation: generateMutation({
    update_match_options_by_pk: [
      {
        pk_columns: { id: $('id', 'uuid!') },
        _set: setupOptionsSetMutation(!!mapPoolId),
      },
      { id: true },
    ],
  }),
});

Lock Behavior

Some options lock once match starts:
computed: {
  isLocked(): boolean {
    return (
      !!this.match &&
      [e_match_status_enum.Veto, e_match_status_enum.Live].includes(
        this.match.status,
      )
    );
  },
}
Once a match enters Veto or Live status, most options cannot be changed. Plan your configuration carefully.

Next Steps

Creating Matches

Apply these options when creating matches

Match Lobbies

Configure lobby access and notifications

Statistics

See how options affect match statistics

Build docs developers (and LLMs) love