-
Notifications
You must be signed in to change notification settings - Fork 0
Forms generation and distribution
Once Step 1 of the Information Collection guide has been completed, the survey can be generated as a set of Google Forms, published and distributed to students.
The project creates survey forms on a teacher basis. Each Google Form contains questions about a single teacher, although multiple forms may be created for the same teacher if they teach students from different groups, streams, specialties or faculties.
This approach has several advantages:
- Students can complete the survey gradually. Instead of evaluating all of their teachers in a single session, respondents can fill out individual forms over several days.
- Forms can be reused across study groups. When several groups from the same specialty attend the same course taught by the same teacher, they can all use the same form. This increases the number of responses while preserving respondent privacy.
- The survey remains anonymous. Google Forms should be configured not to collect email addresses, so respondents' identities are not stored with their answers. At the same time, access to the forms can be restricted to university Google accounts, allowing Google (as trusted authority) to verify that only KPI students can submit responses and that each student can submit the form only once. This approach provides stronger anonymity guarantees compared to a Telegram bot, where user identities are inherently tied to accounts and cannot be guaranteed to be fully separated from responses.
This guide explains the complete process of generating the survey forms, publishing them, and preparing them for distribution to students.
The form generation scripts use the Google Drive API and Google Forms API to create and configure survey forms.
To run the survey automation scripts, you must create OAuth credentials for a desktop application and download the corresponding credentials.json file.
For more information about OAuth authentication for desktop applications, see the official Google documentation
If you do not already have one, create a Google Cloud account (requires a credit card) and sign in to the Google Cloud Console.
- Open the Google Cloud Console
- Create a new Google Cloud project (or select an existing one).
- Make sure the newly created project is selected before proceeding with the following steps.
Enable the following APIs for your Google Cloud project:
The application uses OAuth to access your Google Drive and Google Forms on your behalf.
-
Open the OAuth Consent Screen in the Google Cloud Console.
-
Select External (or Internal if you are using a Google Workspace organization (don't recommend)) and create the application.
-
Fill in the required application information and click Save and Continue.
-
In the Scopes step, add the following OAuth scopes:
https://www.googleapis.com/auth/drive.filehttps://www.googleapis.com/auth/forms.bodyhttps://www.googleapis.com/auth/forms.body.readonlyhttps://www.googleapis.com/auth/forms.responses.readonly
-
In the Test Users step, add the Google account that will be used to run the survey automation scripts. This step is required while the application is in testing mode.
-
Complete the remaining steps to finish the OAuth consent screen configuration.
- Open the Credentials page in the Google Cloud Console.
- Click Create Credentials → OAuth client ID.
- Choose Desktop app as the application type.
- Enter a name for the client (for example, IPT Bee) and click Create.
- Download the generated JSON credentials file (later this guide will refer to it as
credentials.json
The first time the scripts are executed, a browser window will open requesting authorization to access your Google account. After the authorization is completed, a token.json file will be created automatically and reused by subsequent executions.
Note: If you change the requested OAuth scopes or replace
credentials.json, delete the existingtoken.jsonbefore running the scripts again so that a new authorization token can be generated.
Security notice: Never commit, share, or transmit
credentials.jsonortoken.jsonvia non–end-to-end encrypted channels. Both files contain sensitive authentication data and must remain private. They are already excluded from version control via this project’s.gitignoreconfiguration.
All survey forms are generated from a single universal Google Form template that contains the full set of questions. The generation script can selectively include or exclude certain question blocks depending on the teacher’s role (lecturer, practitioner or both).
Even though the Google Forms API technically supports creating forms from scratch, using a pre-built template is required in this implementation. This is due to current limitations of the API (as of August 2025), such as:
- inability to configure certain form settings programmatically (e.g. restricting to one response or disabling email collection),
- lack of support for rich text formatting (bold, italic, etc.)
Because of these constraints, all generated forms are derived from a manually created template.
Before running the generation script, you must create a universal Google Form template manually.
The form must satisfy the following requirements:
-
Proper settings:
- Disable Collect email addresses
- Enable Limit to 1 response
- Enable Allow response editing (recommended)
-
The template must contain four sections:
- 1st section with questions common to all teachers
- 2nd section for practice-only questions
- 3rd section for lecturer-only questions
- 4th section for lecturers and practitioners (usually a combination of the previous two)
Pro-tips how to create a good template:
- only rating and yes/no questions should be required, while open-text questions should remain optional
- allow response editing so students can update open-ended answers later
- clearly explain rating scales, including what the minimum and maximum values represent
- avoid a single generic open questions like “Any other comments”, prefer adding several specific prompts
- design questions collaboratively or reuse validated questions from previous survey iterations
- when introducing new questions, run a small pilot survey to collect feedback before finalizing the template
After creating the form, extract its ID from the URL: https://docs.google.com/forms/d/<here_is_form_id>
Then create a folder in Google Drive (preferably in a shared drive) where all generated forms will be stored and save its ID from its URL.
Once everything is prepared, run the generation script:
uv run scripts/generate_forms.py \
--teacher_data FI-81.json FI-82.json ... FF-82.json \
--template_id <TEMPLATE_FORM_ID> \
--dest_folder_id <FOLDER_ID> \
--secrets_file credentials.json \
--token_file token.json \
--granularity <group|stream|speciality|faculty> \
--stats_granularity <group|stream|speciality|faculty> \
--out_path <output_file_with_all_forms_data>The parameters are:
-
--teacher_data
Paths to JSON files containing structured information about teachers collected on Step 1 of Information collection -
--template_id
ID of the universal Google Form template. It is taken from the form URL:
https://docs.google.com/forms/d/<form_id> -
--dest_folder_id
ID of the Google Drive folder where all generated forms will be stored. A shared Drive folder is recommended for collaboration. -
--secrets_file
Path to the OAuth credentials file (credentials.json) used for Google API authentication. -
--token_file
Path to the file where the OAuth access token is stored and reused. It is created automatically after the first authentication. -
--granularity
Defines how many separate forms are created per teacher depending on the grouping level:-
group— each study group receives its own form per teacher -
stream— each stream (specialty + year of enrollment) receives a separate form per teacher -
speciality— shared for every teacher per specialty -
faculty— one form per teacher per faculty (highest aggregation level, most consolidated)
-
-
--stats_granularity(optional)
Defines the grouping level used for additional optional questions in the form:-
group— respondents specify their study group -
stream— respondents specify their stream (specialty + year of enrollment) -
speciality— respondents specify their specialty -
faculty— respondents specify their faculty
-
-
--out_path
Path to the output JSON file containing metadata about generated forms (form IDs and links).
The generation script performs several modifications to the template to produce a questionnaire tailored to each teacher and target audience. At a high level, the process consists of the following steps:
-
Copy the template
A new Google Form is created by copying the universal template into the destination Google Drive folder specified by
--dest_folder_id. -
Customize the form
The copied form is renamed to the teacher's full name, and the title displayed inside the form is updated accordingly.
-
Optionally add a statistics question
If
--stats_granularityis specified, the script may append an optional question asking respondents to indicate their group, stream, specialty, or faculty, depending on--stats_granularityvalue. This question is intended only for collecting more fine-grained statistics and tracking response activity across students, while still distributing forms at the granularity level specified by--granularity.The question is inserted at the end of the section containing questions common to all teachers.
The question is omitted automatically whenever it would provide no additional information, i.e. when there is only a single possible answer. This typically happens when:
- the generated form already corresponds to a finer granularity than
--stats_granularity(for example, one form is generated per study group, so the respondent's faculty is already known) - the teacher teaches only a single group/stream/specialty/faculty within the audience represented by the generated form.
- the generated form already corresponds to a finer granularity than
-
Adapt the questionnaire to the teacher's roles
For the audience represented by the generated form, the script determines which teacher roles are present and removes the sections corresponding to roles that do not occur.
If only a single role is present, the questions from its section are moved into the common section (immediately before the first non-rating question), producing a single continuous questionnaire.
If multiple roles are present, a "Who was this teacher for you?" question is inserted into the common section, and Google Forms branching is configured to direct respondents to the section corresponding to the selected role.
-
Publish and restrict access
After all transformations are applied, the generated forms are published, i.e. made available for responses.
Access is restricted to users within KPI email domains (
lll.kpi.uaandedu.kpi.ua) to ensure responses come only from authorized participants.If you need to modify access settings, edit the implementation here:
https://github.com/ShkalikovOleh/ipt_survey/blob/178bee0826a47719c3898323e03d07f666c4f3a6/scripts/generate_forms.py#L100
Once the forms are generated, they must be distributed among students. The exact distribution method is not fixed and can be chosen depending on the faculty, available communication channels and group structure. Common approaches include asking group representatives (старости) or individuals responsible for collecting information on the step 1.
An important factor to consider is the chosen --granularity level, as it directly affects how forms can be accessed:
- at faculty level, each teacher has a single form per faculty, which limits respondents to one submission per teacher within that faculty;
- at finer granularities (e.g. group level), multiple forms may exist for the same teacher across different groups, which can allow students to access and potentially respond to multiple forms.
This should be taken into account when selecting a distribution strategy to avoid unintended multiple submissions.
It is highly recommended to announce the survey through official channels with clearly defined dates and a designated feedback/contact channel for reporting issues.
Messages containing form links should always include:
- survey period (start and end dates),
- feedback/contact channel for technical or content-related issues,
- indication of where aggregated results will be published,
- a note that the survey is anonymous,
- a short description of how open-ended responses are handled (e.g. moderation rules or filtering policy).
Pro-tip: it is preferable not to announce the exact publication date of results, but rather provide an approximate timeframe
To simplify distribution of generated forms, you can use the helper bot, which automatically prepares ready-to-send messages with form links for specific audiences (e.g. groups).
The exact text and formatting of messages generated by the helper bot can be customized directly in the source code of the helper bot script
To start the bot, run:
uv run src/bot/helper_bot.py \
--teacher_data <all_teacher_data_files> \
--forms_json <forms_data_from_prev_script> \
--secrets_file credentials.json \
--token_file token.json \
--token <TG_TOKEN>Note: how to obtain the Telegram token is described here:
https://github.com/ShkalikovOleh/ipt_survey/wiki/Results-posting#prerequisites
-
--teacher_data
Paths to JSON files containing teacher information. -
--forms_json
Path to the JSON file with generated forms metadata. -
--secrets_file
Path to Google API OAuth credentials (credentials.json). -
--token_file
Path where the OAuth token is stored and reused. -
--token
Telegram bot token used to post messages.
After starting the helper bot, you can use the following commands in the chat to generate distribution messages with form links:
-
\lgroup <GROUP>
Get all form links for a specific study group.
Example:\lgroup ФІ-81 -
\lstream <STREAM>
Get all form links for a specific stream (specialty + enrollment year).
Example:\lstream F1-8 -
\lspec <SPECIALTY>
Get all form links for a specific specialty.
Example:\lspec F1 -
\lall
Get all form links for the entire faculty.