In this article
Overview
Step-by-step setup guide for business or household phone numbers that can lead to additional interviews
Audience: Survey authors and CATI administrators configuring Forsta Plus survey scripts and CATI scheduling behavior.
Scope: This guide describes three implementation patterns: spawning a follow-up CATI record, spawning a follow-up CATI record with a callback appointment, and moving to another preloaded contact that shares the same phone number.
Before you begin
Confirm the survey contains a telephone number field used by CATI, for example TelephoneNumber.
Confirm the required respondent fields are available in the sample or survey, such as RespondentName, email, parent interview ID, appointment date, time zone, and any hidden variables used by your scripts.
Decide which CATI Extended Status code should be used when creating new calls. The examples use status 1 for a regular scheduled call and status 39 for an appointment callback.
Test the scripts in a non-production project before applying them to a live CATI project.
Adjust question names, answer codes, and status codes to match your own survey definition.
Limitation: Immediate transfer into newly spawned CATI interview records is not currently a supported scenario. While new respondent records can be created and added to CATI during an interview, SetNextCatiInterview() only supports transfer to CATI interviews that already exist within the active CATI interview set (see Scenario 3).
Scenario 1: Create a new interview record for a later call attempt
Use this pattern when the interviewer reaches a business or household and learns that another eligible person can be interviewed at the same phone number, but the additional interview should be handled as a separate future call attempt.
User goal
At the end of the parent interview, create a new child respondent record, pass over key details from the parent interview, and add the child record to the CATI scheduled call list.
Recommended survey fields
Step | Action | Notes / validation |
1 | TelephoneNumber | Stores the connected phone number to be passed to the child record. |
2 | ParentInterviewId or ParentRespId | Stores the interview ID or respondent ID of the original parent interview. |
3 | RespondentName and email, if available | Optional identifying details that can be passed to the child record. |
4 | AnotherPersonAvailable | A question that controls whether the child record should be created. |
Setup steps
Step | Action | Notes / validation |
1 | Add a question near the end of the survey asking whether there is another eligible person at the same number. | Route to the script node only when the interviewer selects yes. |
2 | Add hidden variables for any values you want to pass from the parent record to the child record. | At minimum, pass the telephone number. Include the parent interview ID if you need traceability. |
3 | Create a script node after the yes path. | This node should call CreateRespondentRecord and then AddRespondentToCati. |
4 | Call CreateRespondentRecord with the respondent data that should be copied to the child record. | Use field names that exist in the respondent/sample schema. |
5 | Call AddRespondentToCati using the newly created respondent.respid. | In CATI mode, AddRespondentToCati is processed only when the respondent.respid parameter is included. |
6 | Test by completing a parent interview and checking that a new CATI call is created for the child record. | Validate that the child record is scheduled and contains the expected copied values. |
Script function pattern
function CreateRespondentRecord(respondentData: Respondent) : Respondent
CATI call creation: Use AddRespondentToCati after CreateRespondentRecord. The first parameter is the CATI Extended Status code to apply to the new call. For example, AddRespondentToCati(1, respondent.respid) creates a call using status code 1.
Example script
'RespondentName': f('Details').item(2).get(),
'email': f('Details').item(1).get(),
'TelephoneNumber': f('Details').item(3).get(),
'ParentInterviewId': CurrentID()
});
AddRespondentToCati(1, respondent.respid);
Validation checklist
A new respondent record is created only when another eligible person is available.
The child record contains the expected telephone number and parent interview reference.
The child record appears in CATI as a call to be scheduled or dialed later.
The CATI Extended Status code applied to the child call is correct.
Scenario 2: Create a new interview record with a callback appointment
Use this pattern when another person is available at the same number, but the interviewer needs to schedule the additional interview for a specific callback date and time.
User goal
Capture the preferred appointment time, store it in a hidden appointment variable, create the child respondent record, add it to CATI with the appointment status, and use a CATI scheduling rule to create the custom appointment.
Recommended survey fields
Step | Action | Notes / validation |
1 | APP_DAY | Question used to capture the preferred callback day. |
2 | APP_TIME | Question used to capture the preferred callback time or time range. |
3 | APP_COMMENTS | Optional interviewer notes about the callback. |
4 | AppointmentDate | Hidden variable containing the calculated appointment date and time used by CATI. |
5 | TelephoneNumber | Phone number to pass to the child record. |
6 | TimezoneID | Time zone identifier to pass to the child record when required. |
Setup steps
Step | Action | Notes / validation |
1 | Add appointment questions to capture the preferred callback day and time. | Use clear interviewer-facing labels, such as weekday and time-range choices. |
2 | Add a hidden AppointmentDate variable. | This value should contain the date/time that the CATI scheduling rule will read. |
3 | Add a script that converts the interviewer selections into the AppointmentDate value. | The script should normalize time labels and default missing or open-ended time values according to project requirements. |
4 | Create the child respondent record and pass AppointmentDate, TelephoneNumber, and TimezoneID. | Use CreateRespondentRecord with the appointment-related values included. |
5 | Add the child record to CATI using the appointment Extended Status code. | The example uses 39, but this is user configurable. |
6 | Create a CATI scheduling rule for that Extended Status code. | The rule should run a custom script that reads AppointmentDate and calls CreateCustomAppointment. |
7 | Test with several appointment times. | Confirm the child record is created and the callback appears at the expected appointment time in CATI. |
Example: set the hidden AppointmentDate value
let Apptime;
// Clean the value, keeping only the time.
if (f('APP_TIME').get() == 8) {
// What is the default time when not specified? Confirm with the project owner.
Apptime = '';
} else if (f('APP_TIME').get() == 9) {
// Apptime: how to get other verbatim?
Apptime = '';
} else {
Apptime = f('APP_TIME').ValueLabel()
.replace('Weekends ', '')
.replace('Weekdays ', '')
.trim();
}
// Set a default value if missing.
if (Apptime == '' || Apptime.indexOf('-') < 0) {
Apptime = '09:00-17:00';
}
var nextavail = getNextAvailableDate(weekday, Apptime);
SetRespondentValue('AppointmentDate', nextavail);
Implementation decision: The default time range of 09:00-17:00 is an example. Confirm the default with the project owner before production use.
Example: create the child record and CATI appointment call
var timezoneID = '1';
var AppointmentDate = f('AppointmentDate').get();
var respondent = CreateRespondentRecord({
'AppointmentDate': AppointmentDate,
'TelephoneNumber': telephoneNumber,
'TimezoneID': timezoneID,
'ParentInterviewId': CurrentID()
});
AddRespondentToCati(39, respondent.respid);
Example: CATI scheduling rule script
{
var dumdate = GetRespondentValue('AppointmentDate');
var time: DateTime = DateTime.Parse(dumdate);
CreateCustomAppointment(time);
}
Validation checklist
AppointmentDate is populated before the child respondent is created.
The new child respondent record contains TelephoneNumber, TimezoneID, and AppointmentDate.
The child CATI call uses the Extended Status code that is mapped to the appointment scheduling rule.
The scheduling rule creates a custom appointment at the expected date/time.
Time zone handling is correct for the project.
Scenario 3: Move to another preloaded contact at the same phone number
Use this pattern when the sample already contains separate respondent records for each contact at a business or household and those records share the same phone number. Instead of spawning new records, the interviewer can search for linked records and move directly to the selected contact (whilst staying on the same connected call, if using an integrated dialer).
User goal
At the end of a call, look up other CATI interviews in the same survey that share the current phone number, show them in a selectable list, and then set the next CATI interview to the selected linked record.
Example layout showing a linkedSearch script node, hidden variables for the linked-record results, a selector question, and the MoveToNxtProj script.
Recommended survey fields and nodes
Step | Action | Notes / validation |
1 | phone | Hidden variable used to hold the current phone number for lookup. |
2 | foundLinkedRecords | Numeric variable that stores the number of linked records returned. |
3 | parameterList | Open text list or similar storage used to hold one option per linked record. |
4 | parameterSelector | Question used by the interviewer to select the linked contact to call next. |
5 | ProjectIdPrm | Hidden variable containing the selected linked record ProjectId. |
6 | RespIdPrm | Hidden variable containing the selected linked record RespId. |
7 | ProjResp | Script node that extracts ProjectId and RespId from the selected list value. |
8 | MoveToNxtProj | Script node that calls SetNextCatiInterview with the selected ProjectId and RespId. |
9 | result | Optional variable used to store the result returned by SetNextCatiInterview. |
Setup steps
Step | Action | Notes / validation |
1 | Load one sample record per contact. | Each contact should have its own respondent record, but contacts in the same business or household may share the same TelephoneNumber. |
2 | Add hidden variables and list/selector questions required for the linked-record lookup. | Use the field names above or update the scripts to match your survey. |
3 | Add an initial script node if you need to store the current interview ID or start date. | This appears optional in the example because the assignments are commented out. Keep it only if your project uses those values later. |
4 | At the point where the interviewer asks for another contact, run the linkedSearch script. | The script calls GetCatiInterviews using the current survey project and phone number. |
5 | Populate the linked-record list and show the selector to the interviewer. | The list values store ProjectId, RespId, TelephoneNumber, and RespondentName. |
6 | Run ProjResp after the interviewer selects a linked contact. | This extracts the ProjectId and RespId from the selected list value. |
7 | Run MoveToNxtProj to set the next CATI interview. | This calls SetNextCatiInterview using the selected linked record. |
8 | Test with shared-phone sample data. | Confirm that only the intended linked records are offered and that selecting a record moves to the expected next interview. |
Script: (“linkedsearch”) find linked records by phone number
f('phone').set(f('TelephoneNumber'));
var surveys = [CurrentPID()];
var params = [];
var phoneNumber = [f('phone').get()];
params = GetCatiInterviews(surveys, phoneNumber, '', '');
var currentRespId = CurrentID();
var eligibleParams = [];
for (var i = 0; i < params.length; i++) {
var candidate = params[i];
// Guardrail 1: exclude the current respondent/interview
if (candidate.RespondentId == currentRespId) {
continue;
}
// Guardrail 2: exclude records that should not be called again.
// Adjust these checks depending on which status fields are returned
// by GetCatiInterviews in your environment.
if (candidate.CatiExtendedStatus == 13 || // example: Complete
candidate.CatiExtendedStatus == 14 || // example: Screened out
candidate.CatiExtendedStatus == 5) { // example: Refusal
continue;
}
eligibleParams.push(candidate);
}
f('foundLinkedRecords').set(eligibleParams.length);
var psize = f('parameterList').categories().length;
for (var j = 1; j <= psize; j++) {
f('parameterList_' + j).set(null);
}
for (var k = 1; k <= eligibleParams.length; k++) {
f('parameterList_' + k).set(
'ProjectId:' + eligibleParams[k - 1].ProjectId +
';RespId:' + eligibleParams[k - 1].RespondentId +
';TelephoneNumber:' + eligibleParams[k - 1].TelephoneNumber +
';RespondentName:' + eligibleParams[k - 1].RespondentName +
';'
);
}
Script: (“ProjResp”) extract the selected ProjectId and RespId
var index = labelText.indexOf(prmName);
var startIndex = index + prmName.length + 1;
return labelText.slice(startIndex, labelText.indexOf(';', startIndex));
}
f('ProjectIdPrm').set(GetParameter(f('parameterSelector').valueLabel(), 'ProjectId'));
f('RespIdPrm').set(GetParameter(f('parameterSelector').valueLabel(), 'RespId'));
Script: (“MoveToNxtProj”) move to the selected linked contact
f('result').set(b);
Included guardrails:
Exclude the current respondent from the selectable linked-record list if it appears in the GetCatiInterviews results.
Also filter out records that are complete, screened out, or otherwise not eligible for another call such as refusals (this list may need to be extended with additional statuses that should not be called again).
Validation checklist
Multiple sample records with the same TelephoneNumber are returned by the lookup.
The current record is not accidentally selected as the next interview.
The selector displays enough information for the interviewer to choose the correct contact.
ProjectIdPrm and RespIdPrm are populated after selection.
SetNextCatiInterview returns the expected result and routes the interviewer to the selected linked contact.
Troubleshooting and testing
Step | Action | Notes / validation |
1 | New respondent exists but no CATI call appears. | Confirm AddRespondentToCati is called after CreateRespondentRecord and that respondent.respid is passed. |
2 | CATI call is created with the wrong status. | Check the first parameter passed to AddRespondentToCati and confirm the status code configuration. |
3 | Appointment is created at the wrong time. | Check AppointmentDate format, DateTime.Parse behavior, and TimezoneID. |
4 | Linked-record lookup returns no records. | Confirm the phone number formatting matches across sample records and the lookup variable contains the current telephone number. |
5 | Selector shows stale linked records. | Confirm the parameterList values are cleared before writing the new lookup results. |
6 | Move to next project/contact fails. | Confirm ProjectIdPrm and RespIdPrm were extracted correctly and that the target interview is eligible to be called. |
Recommended end-to-end test cases
Scenario 1: complete a parent interview, indicate another person is available, and confirm a new scheduled call is created.
Scenario 1 negative test: indicate no additional person is available and confirm no child record or CATI call is created.
Scenario 2: create an appointment callback using a specific date and time and confirm the CATI appointment appears correctly.
Scenario 2 edge test: use a missing or open-ended time selection and confirm the configured default time is applied.
Scenario 3: preload three contacts with the same phone number, select a different contact, and confirm the next CATI interview is set to that record.
Scenario 3 edge test: complete or ineligible linked contacts should not be offered, or should be clearly handled according to project rules.
Implementation reminders
Use consistent phone number formatting. Linked-contact lookup depends on matching the phone number value.
Use hidden variables for technical values that should not be edited by the interviewer.
Keep Extended Status code usage consistent across survey scripts and CATI scheduling rules.
Record parent-child relationships when spawning new records so reporting can distinguish original contacts from generated follow-up records.
Document any project-specific defaults, such as appointment time range, time zone, and eligibility filters.