Inhaltsverzeichnis

Quota

In collaboration with panel providers, quoted samples are often booked. The questionnaire is then responsible for the quota stop: If there are enough questionnaires for a demographic group, further participants of this group are sent back to a quota-full address of the panel provider.

Note: For other forms of recruitment a quota stop is usually not useful. The consequence would be that the majority of interested participants would be rejected – but at the same time, recruitment would still be necessary to complete the missing demographic groups.

Tip: Use the debug mode and view the debug information to check the function of the quota stop and if it does not work immediately in the test (e.g. with very small quotas)(Problem Solution for Filters).

Minimum quota

A survey should end as soon as a certain number of cases is reached.

In the questionnaire, create a text that should be displayed when the number of cases is reached. Afterwards you should insert the following PHP code at the top of the first page of the questionnaire. The example code assumes that the text is named „QS01“ and that the survey should end after 250 completed questionnaires.

// Counting completed questionnaires
$finished = statistic('count', 'FINISHED');
// Filter to stop Quota
if ($finished >= 250) {
  // Show text
  text('QS01');
  // go on hiding the button
  buttonHide();
  // Stop showing new content of this page
  pageStop();
}

Note:This PHD-Code counts evry case with MODE „Interview“ and FINISHED 1. These can also be cases where a screenout occurs using redirect(). In debug mode, the cases are counted independently of the MODE variable.

Do not use the count of completed cases using 'FINISHED' in addition to a more differentiated quota. Cases that were rejected due to a quota-out using redirect() are counted as completed cases by statistic('count', 'FINISHED'). In such cases, you can work with the frequency of LASTPAGE instead. If the redirect() command is on page 25 and all respondents answer page 24 beforehand, the code could look like this.

// Counting relevant questionnaires
$finished = statistic('count', 'LASTPAGE', 24);
// Filter for quota stop
// (go on just like above)

Filtering

If you want to ensure that only cases with certain properties are counted, create an internal variable (in the following example „QS02_01“) and only give this variable the value 2 if a case fulfills the desired criteria. For example, if the following PHP code is placed on the penultimate page of the questionnaire, then only cases that reach the penultimate page and have taken at least 10 minutes (600 seconds) to get there will be counted.

$time = caseTime('hitherto');
if ($time >= 600) {
  put('QS02_01', 2);
}

The actual quote stop then no longer refers to the „FINISHED“ variable, but to the internal variable. The following PHP code would then be placed on the first page of the questionnaire, for example.

// Count valid questionnaires
$valid = statistic('count', 'QS02_01', 2);
// Filter just like above
if ($valid >= 250) {
  text('QS01');
  buttonHide();
  pageStop();
}

Functionality

The quota limits by demographic groups includes the following steps:

  1. Query the quota characteristics of a person using value().
  2. Counting how many persons with this characteristic value or with this combination of characteristic values have already been surveyed using statistic().
  3. Comparison of the count with a quota table showing how many people are needed per demographic cell.
  4. Rejecting people if there are already enough cases for a demographic cell, using redirect().

The term „demographic cell“ or „demographic group“ means a combination of the characteristics to be quoted (e.g. „male participants between 15 and 25 years“ if age and gender are quoted).

In principle, unrelated and related quota can be examined. In the case of unrelated quota, the characteristics are checked one after the other („Are there already enough questionnaires from male participants? Are there already enough questionnaires from young participants?“). Here the marginal sums of the distribution are checked. Accordingly, in the unrelated quota system, it would be possible to fill the quota with young women and old men – without any young men.

In the linked quota system, the demographic cells are checked („Are there already enough questionnaires from young male participants?“). The linked quota system is thus less susceptible to systematic distortions (conflicting demographic characteristics) – but more potential participants are also rejected.

Please note the interaction between statistic() and redirect(): The function redirect() marks the questionnaires of rejected participants as „completed“ (FINISHED=1), so that they are counted by statistic(). In order to avoid wrong counts, the variables that were queried in the questionnaire are not counted directly: Instead, with the Complete-Redirect the quota characteristics are copied to internal variables by means of put(), which can then be counted. Thus, 2 separate PHP codes are required for the quota.

  1. After querying the quota characteristics (on the following page), the value specified by the participant is checked against the number of existing cases.
  2. Directly before the Complete-Redirect, the value of the quota characteristic is copied into an internal variable.

If the quota feature has to be recoded first, this PHP code is used in both parts.

Technical implementation (unrelated quotas)

The technical implementation is done by Introduction to PHP and comprises several steps. These are first explained here for the verification of unrelated quotas.

In the following two characteristics are quoted as examples: Age (open query in variable „SD01_01“) and gender (closed query in variable „SD02“). It is advisable to define quote questions as mandatory questions.

Definition of quota

First, a list (Array) is required, which specifies the desired number of participants for each characteristic value. For unrelated quota, one quota table per feature is required.

In the following example, the screenout is integrated directly in the quota check. However, an upstream screenout would also be possible.

$quotaAge = [
  2 => 200, // 200 persons in age group 2 (18-30 years)
  3 => 250, // 250 persons in age group 3 (31-50 years)
  4 => 150 // 150 persons in age group 4 (51-68 years)
];
$quotaGender = [
  1 => 300, // 300 women (code 1)
  2 => 300 // 300 men (code 2)
];

Please note that there are no entries in the table for age groups 1 (persons under 18 years) and 5 (persons older than 68 years). The same applies to gender 3 (persons who assign themselves to another gender). This is represented in the screenout (below) by the function array_key_exists().

Read out and recode characteristics

The characteristic value of the current participant is read out using value() and, if necessary, recoded with an IF construction. In this case the age (open input) has to be recoded.

// Gender is read out directly
$gender = value('SD02')
// The age is recoded
$age = value('SD01_01')
if ($age < 18) {
  $ageGroup = 1;
} elseif ($age <= 30) {
  $ageGroup = 2;
} elseif ($age <= 50) {
  $ageGroup = 3;
} elseif ($age <= 68) {
  $ageGroup = 4;
} else {
  $ageGroup = 5;
}

Counting the cases in hand

Now the system uses statistic() to check how many data records with the quota characteristics already exist in the data record. This value is then compared with the quota defined above.

Important: For the PHP code to work correctly, all parts must be in the same PHP code block. PHP-Variables such as $quotaAge and $ageGroup are only valid within one code block.

In the following code not the variables used to query the quota characteristics („SD01_01“ and „SD02“) are counted, but internal variables („SD03_01“ and „SD03_02“).

Important: The internal variables must be created manually in advance in the question catalogue.

// Retrieval of the available cases for this characteristic
$casesAge = statistic('count', 'SD03_01', $ageGroup);
$casesGender = statistic('count', 'SD03_02', $gender);
 
// Screenout
if (!array_key_exists($ageGroup, $quotaAge) || !array_key_exists($gender, $quotaGender)) {
  redirect('https://www.panelanbieter.de/?xyz=screenoutGHIJKI&uid=%reference%');
}
 
// Reading the quota for the specified characteristics
$maxPerAge = $quotaAge [$ageGroup];
$maxPerGender = $quotaGender[$gender];
 
// quota stop
if (($casesAge >= $maxPerAge) || ($casesGender >= $maxPerGender)) {
  redirect('https://www.panelanbieter.de/?xyz=quotaABCDEF&uid=%reference%');
}

The Boolean operator || is an OR operation between the two conditions. So if there are either enough cases for age or enough cases for gender, a QuotaFull redirect is performed.

You can get the redirect link from the Panel provider. It is important that you submit the participant ID. The example uses the placeholder %reference%. Details can be found here: Working with External Panel Providers.

Important: The participant's response will not be transmitted to the server until the participant has sent it by clicking „Next“. If the questions „SD01“ and „SD02“ are on page 2 of the questionnaire, value() and thus the PHP code above can be placed on page 3 at the earliest.

Copy quota characteristics

Finally, the quota characteristics must be copied to the internal variables. This means directly before the Complete-Redirect, which is usually placed on the penultimate page of the questionnaire.

To do this you need redo the PHP code from the section Read out and recode characteristics (above) and in the same PHP code block directly below the function put() to set the internal variables.

put('SD03_01', $ageGroup);
put('SD03_02', $gender);

This is usually followed by the Complete redirect.

redirect('https://www.panelanbieter.de/?xyz=completeDEFGHI&uid=%reference%');

Quota check at the beginning

If you work with linked quota, you must define a larger number of quota: One threshold per demographic cell. With 3 values for age and 2 values for gender, this makes a total of 6 quota.

In the following PHP code, a demographic cell is defined by a code of age (2-4) and gender (1-2). For the sake of clarity, the 6 quota are noted in 3 lines with 2 quota each – technically it makes no difference if the comma is followed by a line break.

$quota = [
  '2-1' => 100, '2-2' => 100, // 100 persons per gender for age group 1
  '3-1' => 125, '3-2' => 125, // 125 persons per gender for age group 2
  '4-1' => 75, '4-2' => 75 // 75 persons per gender for age group 3
];

The readout of the quota-relevant characteristics and the recoding is initially carried out in the same way as for the unrelated quota.

// Gender is read out directly
$gender = value('SD02')
// Age is recoded
$age = value('SD01_01')
if ($age < 18) {
  $ageGroup = 1;
} elseif ($age <= 30) {
  $ageGroup = 2;
} elseif ($age <= 50) {
  $ageGroup = 3;
} elseif ($age <= 68) {
  $ageGroup = 4;
} else {
  $ageGroup = 5;
}

However, an additional variable is defined, which contains the code of the demographic cell. The dot (.) is used in PHP to join texts (concatenate strings).

// Definition of a variable with age group and gender
// 3 and 2 become '3-2' here
$demGroup = $ageGroup.'-'.$gender

The quota check is now performed for this (combined) characteristic. Again, an internal variable (SD04_01) is used, which must be defined in advance in the question catalog.

// Retrieval of the available cases for this characteristic
$cases = statistic('count', 'SD04_01', $demGroup);
 
// screenout
if (!array_key_exists($demGroup, $quota)) {
  redirect('https://www.panelanbieter.de/?xyz=screenoutGHIJKI&uid=%reference%');
}
 
// Reading the quota for the demographic group
$maxPerGroup = $quota [$demGroup];
 
// quota stop
if ($cases >= $maxPerGroup) {
  redirect('https://www.panelanbieter.de/?xyz=quotaABCDEF&uid=%reference%');
}

Saving the cell code

Before the Complete-Redirect, the code for the demographic cell must be saved in the internal variable.

// Saving the group membership in the internal variable SD04_01
put('SD04_01', $demGroup);

In order for this code to work, the quota characteristics must also be retrieved and recoded. And of course they have to be concatenated to the cell code $demGroup. The complete code for the penultimate questionnaire page including Complete-Redirect looks like this

// Gender is read out directly
$gender = value('SD02')
// Age is recoded
$age = value('SD01_01')
if ($age < 18) {
  $ageGroup = 1;
} elseif ($age <= 30) {
  $ageGroup = 2;
} elseif ($age <= 50) {
  $ageGroup = 3;
} elseif ($age <= 68) {
  $ageGroup = 4;
} else {
  $ageGroup = 5;
}
 
// Definition of a variable with age group and gender
// 3 and 2 become '3-2' here
$demGroup = $ageGroup.'-'.$gender
 
// Store the group membership in the internal variable SD04_01
put('SD04_01', $demGroup);
 
// Complete-Redirect
redirect('https://www.panelanbieter.de/?xyz=completeDEFGHI&uid=%reference%');

Searching for mistakes

The implementation of quotas is not entirely trivial at the moment (optimization in progress) – and mistakes keep appearing in the code. For example, cases are rejected even though the quotas have not yet been met. For example, cases are rejected even though quotas have not yet been met.

We expect you to be familiar with the function about Debug-Information (see Fragebogen-Probleme lösen).

Two modifications are very helpful to show all important information for the search of mistakes.

(1) Redirects should be temporary deactivated

You should deactivate the redirects so that you can see the Debug-Information. You can comment out the redirect() with two slashes (//) and thus deactivate it. Add pageStop(), instead so that no further content is executed on the page. Using html() you can see one short information if your IF filter looks like this in productive operation…

// Quotenstopp
if (($casesAge >= $maxPerAge) || ($casesGender >= $maxPerGender)) {
  redirect('https://www.panelanbieter.de/?xyz=quotaABCDEF&uid=%reference%');
}

… dann ändern Sie den Code zur Fehlersuche wie folgt.

// Quotenstopp
if (($casesAge >= $maxPerAge) || ($casesGender >= $maxPerGender)) {
  // redirect('https://www.panelanbieter.de/?xyz=quotaABCDEF&uid=%reference%');
  html('<p>Redirect ausgelöst</p>');
  pageStop();
}

(2) Show quota count

In the debug information, you can already see which values statistic() returns. But with the function debug() you can also display which values your quotation (the array with the quotas) returns for the current case.

Simply add a line debug() for all filter-relevant variables. For the filter above, this would look like this.

// Show additional information
debug($casesAge);
debug($maxPerAge);
debug($casesGender);
debug($maxPerGender);
 
// Quota stop
if (($casesAge >= $maxPerAge) || ($casesGender >= $maxPerGender)) {
  // redirect('https://www.panelanbieter.de/?xyz=quotaABCDEF&uid=%reference%');
  html('<p>Redirect ausgelöst</p>');
  pageStop();
}

This allows you to immediately understand why a redirect is triggered. If you are still unable to understand why these (possibly incorrect) values are averaged, display other variables, e.g. where the quota limits are read out. The code in the example above is as follows.

// Read out the quotas for the specified characteristics
$maxPerAge    = $quotaAge[$ageGroup];
$maxPerGender = $quotaGender[$gender];

For example, if you do not know where the value for $maxPerAge comes from, you can display the array and the age category.

// Read out the quotas for the specified characteristics
$maxPerAge    = $quotaAge[$ageGroup];
$maxPerGender = $quotaGender[$gender];
 
// Show additional information
debug($ageGroup);
debug($quotaAge);
debug($maxPerAge);

These information are helping too in Online-Support, if you need support with the implementation of your filters.