Custom JavaScript is available on approved accounts only. Write to [email protected] to request access. Until your account is approved, a humanize schema that includes a script is rejected when you save it, and no part of that schema is saved.
Checking access
Adding a script
Scripts go in the humanize schema, underquestions[question_name].javascript.hooks. A hook maps an event to the script that runs on it. The only event is "question.ready", which fires once the question has been rendered and its inputs are on the page.
Coop.patch_human_survey_humanize_schema:
"javascript": None on a question to remove its script.
Most question types support javascript, including survey messages; see Humanize schema for the list. compute and image_generation questions do not: they run in the background and never appear on the page.
Writing a hook
A hook is the body of a function, not a function. Write the statements you want to run; don’t wrap them infunction () { ... }.
Inside a hook you have:
context carries nothing that identifies the respondent.
Each question’s hook runs once when that question appears. If the same script is attached to several questions, it runs once for each, and context.questionName tells them apart.
Recording events with ep.log
ep.log(eventName, payload) records an event against the respondent’s response. Use it for anything you want to analyse later: timings, clicks, which condition a respondent saw.
eventNamemust be a non-empty string. Names longer than 200 characters are cut to 200.payloadis optional and must be convertible to JSON: objects, arrays, strings, numbers, booleans andnull. A payload that isn’t (a page element, an object that refers to itself) is not recorded, and a warning appears in the browser console.- A payload larger than 4,000 characters, measured as JSON, is not recorded.
- Each response records at most 10,000 events.
ep.log returns nothing. Events are sent in batches in the background, so don’t wait on it.
What a script may do
Scripts can build interface inside the survey, read and write answers, control when respondents can move on, measure behaviour, randomise conditions, read parameters from the page URL, load images, audio, video and other media to show, and use the camera, microphone or location for a task the respondent is told about. A script can also load a well-known, widely used library, such as d3, Chart.js or lodash, from a public CDN like cdnjs, jsDelivr or unpkg, at a pinned version (for examplehttps://cdn.jsdelivr.net/npm/[email protected]/dist/d3.min.js, not d3@latest). Your own code must still be plain JavaScript written in the script itself.
A script can’t be saved if it:
- Loads code from anywhere else: an unfamiliar or personal site, a paste site, a little-known or custom package, source hosted somewhere other than a named library, or a URL put together while the script runs.
- Builds code at runtime, for example by passing a constructed string to
eval,new Function,setTimeoutorsetInterval, or by inserting markup that contains a script. - Makes any request to Expected Parrot, or sends respondent data anywhere else.
ep.logis how data leaves a script. - Reads cookies, tokens, credentials, or storage it didn’t create.
- Is obfuscated or minified so that what it does can’t be read from the source. This applies to your script, not to a well-known library it loads.
- Asks for passwords or payment details, or imitates a login or other dialog.
- Collects anything unrelated to taking the survey, or uses the camera, microphone or location covertly.
- Keeps running after the respondent has finished or left the survey.
- Misleads or traps the respondent, for example by opening popups, preventing them from leaving, or hiding the survey’s own notices.
- Uses the respondent’s device for something other than the survey.
Limits
- Each hook can be at most 64,000 characters, and all hooks on one question at most 256,000.
- One save can add at most 25 different new scripts. A script used unchanged on several questions counts once, and scripts the survey already has don’t count. Save larger surveys in smaller batches.
Retrieving events
UseCoop.get_all_human_survey_events to get every event a survey has recorded, oldest first:
is_preview, so leave them out of an analysis. Events that arrive while the download runs are included, and no event comes back twice.
To fetch new events later without downloading everything again, pass the id of the last event you downloaded as after. Take it from the full download, before filtering out previews:
Fetching only new events is useful for checking your scripts while a survey is collecting, but it can occasionally miss an event that was still being saved when you downloaded. For analysis, download the full log once fielding has ended, at least an hour after the last response.
Coop.get_human_survey_events. It takes after and limit (at most 200, the default), and returns {"events", "next_cursor", "has_more"}. Pass next_cursor as after to get the next batch while has_more is True. next_cursor is returned even when there is nothing more, so you can keep it and use it later.
To see how many events a survey has without downloading them, use Coop.count_human_survey_events. The count is as of the call; on a survey still collecting, a download started afterwards can return more.
Each event includes:
session_state is one of:
"complete": the session ended normally and no events are missing."truncated": some events from this session are known to be missing, for example because they broke the limits above."unknown": no events are known to be missing, but the session never signalled that it ended, for example because the respondent’s browser closed or lost its connection. Its log may or may not be whole.
session_state describes the whole session, so every event from one session carries the same value.
From the command line
Theep CLI covers the same steps. --javascript takes QUESTION:HOOK=FILE, naming the question, the hook, and a file holding the script:
--all requires --output, which can end in .json or .jsonl. Every result includes next_cursor, the value to pass as --after next time. If a download fails part way, no output file is written. As with the Python methods, use --after for checking a survey while it collects, and a full download once fielding has ended for analysis.