Python reference¶
Use the Python API to add parsing, reports, or Qualtrics API calls to your own scripts. Install the package first, following installation. Run scripts from this repository with uv run python your_script.py.
Public imports¶
The package root exports the offline workflow and the API client:
from qualtrics import (
EntitySet,
QualtricsClient,
ReportAnalytics,
SemanticModel,
TranslationRequest,
__version__,
analyze_entities,
build_semantic_model,
load_entities,
merge_entity_sets,
parse_survey,
parse_surveys,
prepare_translations,
render_report,
write_entities,
write_semantic_model,
)
The canonical report interface is from qualtrics.ui import render_report; you can also use the root import above. Install qualtrics[ui] before generating a report. Base SDK/data imports work without Jinja, Typer, or Rich; UI rendering does not require CLI dependencies.
Importing these names does not read credentials or make API calls. The client reads connection settings when you construct it; service methods make requests when you call them.
Migrate earlier deep imports¶
The package layout now has four implementation packages: api, cli, ui, and _common. The earlier qualtrics.models, qualtrics.parsers, qualtrics.analytics, qualtrics.serialization, qualtrics.reporting, and qualtrics.services paths have been removed. Update imports to the public interfaces:
| Earlier import | Replacement |
|---|---|
from qualtrics.models import EntitySet, merge_entity_sets |
from qualtrics import EntitySet, merge_entity_sets |
from qualtrics.models.semantic import SemanticModel, build_semantic_model |
from qualtrics import SemanticModel, build_semantic_model |
from qualtrics.parsers import parse_survey, parse_surveys |
from qualtrics import parse_survey, parse_surveys |
from qualtrics.analytics import ReportAnalytics, analyze_entities |
from qualtrics import ReportAnalytics, analyze_entities |
from qualtrics.serialization import load_entities, write_entities |
from qualtrics import load_entities, write_entities |
from qualtrics.serialization.semantic import write_semantic_model |
from qualtrics import write_semantic_model |
from qualtrics.reporting import render_report |
from qualtrics.ui import render_report or from qualtrics import render_report |
from qualtrics.services import merge_entity_sets |
from qualtrics import merge_entity_sets |
Use the root imports for shared data operations. Treat _common and its submodules as private implementation details; they are not supported application imports. Existing root imports and the cli and ui extras retain their behavior. The base installation includes the API SDK and PyArrow dependencies.
Offline functions¶
The signatures below use Path from pathlib and Sequence and Callable from collections.abc.
parse_survey(
source_path: str | Path,
qsf_path: str | Path | None = None,
survey_id: str | None = None,
*,
flow_path: str | Path | None = None,
) -> EntitySet
parse_surveys(
source_paths: Sequence[str | Path],
qsf_paths: Sequence[str | Path] | None = None,
) -> EntitySet
merge_entity_sets(entity_sets: list[EntitySet]) -> EntitySet
write_entities(entities: EntitySet, folder: str | Path, format: str = "json") -> None
load_entities(folder: str | Path | None = None, **paths: str | Path) -> EntitySet
prepare_translations(
entities: EntitySet,
*,
language: str | None = None,
translate: Callable[[TranslationRequest], str] | None = None,
question: Callable[[TranslationRequest], str] | None = None,
field: Callable[[TranslationRequest], str] | None = None,
answer_option: Callable[[TranslationRequest], str] | None = None,
comment: Callable[[TranslationRequest], str] | None = None,
) -> EntitySet
render_report(entities: EntitySet, output: str | Path) -> None
analyze_entities(entities: EntitySet) -> ReportAnalytics
build_semantic_model(entities: EntitySet) -> SemanticModel
write_semantic_model(
model: SemanticModel,
folder: str | Path,
format: str = "parquet",
) -> None
| Function | Behavior and constraints |
|---|---|
parse_survey |
Accepts a CSV, a ZIP containing one CSV, or a wildcard pattern matching several inputs. Discovers a same-stem .qsf then .json definition if you omit qsf_path. A survey_id override applies to one input only. |
parse_surveys |
Expands wildcard patterns in each supplied path, sorting each pattern's matches. Explicit definitions pair with inputs by position; supply one per input or omit them for adjacent discovery. |
merge_entity_sets |
Combines distinct survey IDs and deduplicates identical records in the two catalogs. Raises ValueError for repeated survey IDs or conflicting records with the same catalog ID. |
write_entities |
Writes nine core entities and derived comments as json, csv, or parquet, plus manifest.json. Prepared targets are nullable comments columns, not a sidecar file. Creates the folder and overwrites matching files. |
load_entities |
Loads entity files named for their tables. Explicit keyword paths use table names, such as responses="responses.json"; manifest="metadata.json" selects a separate manifest. When explicit table paths share a folder, its sibling manifest.json is loaded automatically. Validates the full contract when you supply a folder; without a folder, validates the supplied subset's keys and relationships. Rejects multiple formats for the same entity in a folder. |
prepare_translations |
Calls your shared or kind-specific callback for missing definition labels and written answers. QSF labels win; callback-generated choice labels never resolve categorical facts. Returns a new collection; without a callback, it makes no service calls. |
render_report |
Writes a self-contained HTML report with the built-in design. The output's parent directory must exist. Overwrites the target file. |
analyze_entities |
Calculates response counts, question roles, answer groupings, and unused or unanswered content for reports. Returns a ReportAnalytics without requiring the ui extra. |
build_semantic_model |
Requires a complete, valid entity collection. Returns nine tables; prepared text and freshness flags are columns of fact_comments. |
write_semantic_model |
Writes all nine tables as json, csv, parquet, or one SQLite database. Creates the folder and overwrites matching files. |
The Python writers do not apply the CLI combine and semantic commands' occupied-output checks. Choose a fresh output directory for each run or format. The base package supports reading and writing Parquet.
Use prepare_translations(entities, language="EN", comment=your_callback) to prepare written answers alone; pass translate=your_callback to use one structured callback for labels and comments. Each callback receives a TranslationRequest. To attach translations prepared outside Python, use the CLI import command with a hash-checked CSV or Parquet file. Raw answers remain unchanged and the toolkit never calls a translation service without your callback.
Parse, save, and report¶
from pathlib import Path
from qualtrics import (
build_semantic_model,
load_entities,
parse_survey,
render_report,
write_entities,
write_semantic_model,
)
def main() -> None:
output = Path("output/customer")
output.mkdir(parents=True, exist_ok=True)
entities = parse_survey("data/customer.csv", "data/customer.qsf")
write_entities(entities, output / "entities") # JSON by default.
saved = load_entities(output / "entities")
render_report(saved, output / "report.html")
semantic = build_semantic_model(saved)
write_semantic_model(semantic, output / "semantic", format="csv")
print(f"Wrote a report for {len(saved.responses)} responses")
if __name__ == "__main__":
main()
Use the downloadable inputs in your first report, or follow parse exports with your own data.
render_report selects presentations from the question and field metadata: choice distributions, matrix tables, numeric summaries, or text summaries. It does not infer numeric measurements from text values. Preserve the metadata from parse_survey or load_entities when constructing your own workflows. See question-specific summaries for the percentage denominators and numeric statistics.
Collections and table names¶
EntitySet is a dataclass with lists of dictionaries named surveys, sections, question_catalog, question_field_catalog, questions, answer_options, question_fields, responses, response_answers, and comments. Its keyword-only survey_manifests map holds the per-survey metadata in memory. Prefer parse_survey or load_entities to construct a collection with the metadata needed for strict validation.
SemanticModel also includes display-language and localized-label tables. fact_comments remains one row per original written answer, with optional prepared target columns and translation_is_current__CODE freshness flags. dim_questions has one row per exported question field.
entities.comments and semantic.fact_comments are derived text-answer subsets. They reuse response_answer_id, preserve the answer text, and copy nullable user_language only from the linked response. The original nine entity lists remain authoritative; a legacy folder without comments reconstructs it from available types. New fields carry nullable boolean is_comment_field on question_fields and dim_questions so source classification survives serialization. See the comments contract for membership and validation rules. Do not count comments again when using the complete answer table.
Use analyze_entities(entities) to calculate report metrics in Python. Its ReportAnalytics result includes response_count, finished_count, question_roles, and the question, field, and answer lookups used by HTML reports.
Use the entity model and DBML schema for columns, keys, and relationships. The glossary explains the terminology.
API client¶
QualtricsClient(
api_token: str | None = None,
*,
data_center: str | None = None,
base_url: str | None = None,
timeout: float = 30.0,
max_retries: int = 3,
retry_backoff: float = 1.0,
transport: httpx.BaseTransport | None = None,
)
Omit connection arguments to read environment variables and .env. See configuration for precedence, URL resolution, and timeouts. Use with QualtricsClient() as client: to close the HTTP connection on exit; otherwise call client.close(). QualtricsClient.from_env(**kwargs) is a compatibility alias for construction with the same keyword arguments.
List surveys with error handling¶
import httpx
from qualtrics import QualtricsClient
from qualtrics.api import QualtricsAPIError, QualtricsExportError
def main() -> None:
try:
with QualtricsClient() as client:
for survey in client.surveys.iter():
print(survey.id, survey.name)
except QualtricsAPIError as error:
print(f"Qualtrics HTTP {error.status_code}: {error}")
if error.request_id:
print(f"Request ID: {error.request_id}")
except QualtricsExportError as error:
print(f"Import or export job failed: {error}")
except httpx.HTTPError as error:
print(f"Connection failed: {error}")
except ValueError as error:
print(f"Check connection settings or request data: {error}")
if __name__ == "__main__":
main()
The main guard keeps importing this script from making API calls. For response downloads and definitions, follow API access.
API services¶
Service attributes group endpoints by purpose. The signatures below omit self. Any comes from typing; Iterator comes from collections.abc. Response models below are Pydantic models: use their snake_case attributes, .model_dump(), or .model_dump_json().
client.surveys¶
list(*, offset: int | None = None) -> SurveyPage
iter() -> Iterator[SurveySummary]
get(survey_id: str) -> dict[str, Any]
update(survey_id: str, changes: SurveyUpdateRequest | dict[str, Any]) -> dict[str, Any] | None
list returns one page; iter follows nextPage links. update sends changes to the live survey. SurveyUpdateRequest supports name, is_active, expiration, and owner_id; you can also pass API field names such as isActive.
client.survey_definitions¶
get(survey_id: str) -> SurveyDefinition
get_flow(survey_id: str) -> dict[str, Any]
create(definition: dict[str, Any]) -> dict[str, Any]
delete(survey_id: str) -> dict[str, Any] | None
get_metadata(survey_id: str) -> dict[str, Any]
update_metadata(survey_id: str, metadata: dict[str, Any]) -> None
get returns a wrapper with survey_id, survey_name, and the raw definition in payload. You can save .model_dump_json() as a .json definition and pass it to parse_survey. create, delete, and update_metadata change remote data.
get_flow reads the configured flow root with its ordered children through the existing retry transport. Save it as JSON and pass its path as parse_survey(..., flow_path=...) for one input. Flows already included in a QSF or API definition are preserved automatically. The parser stores report-safe flow metadata in the export folder's manifest.json, keyed by survey ID; surveys stays scalar. See survey flow for a complete example and supported walkthrough behavior.
client.survey_quotas¶
list(survey_id: str, *, offset: int | None = None) -> SurveyQuotaPage
iter(survey_id: str) -> Iterator[SurveyQuota]
client.quotas is an alias. list rejects negative offsets. A quota has id, name, count, quota, logic_type, and combinations; each combination has count, quota, and description.
client.responses: exports¶
client.response_exports is an alias for the same service.
start(survey_id: str, options: ResponseExportRequest | None = None) -> ExportProgress
progress(survey_id: str, progress_id: str) -> ExportProgress
wait(
survey_id: str,
progress_id: str,
*,
poll_interval: float = 1.0,
timeout: float = 900.0,
on_progress: ExportCallback | None = None,
) -> ExportProgress
download(survey_id: str, file_id: str) -> httpx.Response
export(
survey_id: str,
output: str | Path,
*,
options: ResponseExportRequest | None = None,
naming: FilenameStrategy = FilenameStrategy.SURVEY_ID,
filename: str | None = None,
survey_name: str | None = None,
poll_interval: float = 1.0,
timeout: float = 900.0,
on_progress: ExportCallback | None = None,
) -> ExportResult
export starts, waits for, downloads, and saves an export. It returns the saved path, survey_id, progress_id, file_id, format, and optional continuation_token. The default request uses labeled CSV with compression, resulting in a ZIP. Set ResponseExportRequest(compress=False) for an uncompressed export. See the CLI naming rules for output path behavior.
on_progress receives an ExportEvent with survey_id, stage, and optional percent_complete. Import ExportCallback and ExportEvent from qualtrics.api. The full export emits starting, exporting, downloading, and complete; wait emits only polling updates. Completion is emitted after the local file is saved. Callbacks run in the calling thread. See progress callbacks and safe retries for an example.
wait requires a completed status and file ID; failed or timed-out jobs raise QualtricsExportError. download returns the HTTP response without saving a file.
client.responses: imports and filters¶
import_file(
survey_id: str,
source: str | Path,
*,
format: ImportFormat = ImportFormat.CSV,
) -> ImportProgress
import_url(
survey_id: str,
file_url: str,
*,
format: ImportFormat = ImportFormat.CSV,
) -> ImportProgress
import_progress(survey_id: str, progress_id: str) -> ImportProgress
wait_for_import(
survey_id: str,
progress_id: str,
*,
poll_interval: float = 1.0,
timeout: float = 900.0,
) -> ImportProgress
list_filters(survey_id: str, *, offset: int | None = None) -> SurveyFilterPage
iter_filters(survey_id: str) -> Iterator[SurveyFilter]
Imports add response data to a live survey. Pass ImportFormat.CSV or ImportFormat.JSON. import_file sends local file bytes; import_url sends a file URL for Qualtrics to fetch. Poll with the returned progress_id. Failed or timed-out imports also raise QualtricsExportError.
list_filters returns one page of saved filters; iter_filters follows pagination. Import SurveyFilter and SurveyFilterPage from qualtrics.api.models when you need their types; they are not re-exported from qualtrics.api.
Request models and enums¶
Import the main request models from qualtrics.api:
from qualtrics.api import (
FilenameStrategy,
ImportFormat,
ResponseExportRequest,
ResponseImportRequest,
SurveyUpdateRequest,
)
ResponseExportRequest accepts the fields below. Both Python names and Qualtrics aliases work, for example use_labels=False and useLabels=False.
| Python field | API alias | Default |
|---|---|---|
format |
format |
"csv"; also tsv, json, ndjson, xml, spss |
compress |
compress |
True |
use_labels |
useLabels |
True |
new_line_replacement |
newlineReplacement |
None |
include_display_order |
includeDisplayOrder |
False |
include_label_columns |
includeLabelColumns |
False |
start_date, end_date |
startDate, endDate |
None |
filter_id |
filterId |
None |
question_ids |
questionIds |
None |
survey_metadata_ids |
surveyMetadataIds |
None |
embedded_data_ids |
embeddedDataIds |
None |
limit |
limit |
None |
continuation_token |
continuationToken |
None |
allow_continuation |
allowContinuation |
False |
sort_by_last_modified_date |
sortByLastModifiedDate |
False |
ID collections take lists of strings; date values and tokens take strings; limit takes an integer. The SDK passes these filters to Qualtrics. It does not automatically continue an export from a returned continuation token.
ResponseImportRequest requires file_url (alias fileUrl) and defaults to format=ImportFormat.CSV. FilenameStrategy provides SURVEY_ID, SURVEY_NAME, QUALTRICS, and CUSTOM. ExportStatus provides IN_PROGRESS, COMPLETE, and FAILED.
The API package also re-exports ExportFormat, ExportProgress, ExportResult, ImportProgress, SurveyDefinition, SurveyPage, SurveySummary, SurveyQuota, SurveyQuotaCombination, SurveyQuotaPage, QualtricsSettings, and the service classes. ResponseExportsAPI is the compatibility name for ResponseImportsExportsAPI.
Low-level transport and compatibility methods¶
Use the services above for covered endpoints. For another JSON endpoint:
client.request(
method: Literal["GET", "POST", "PUT", "PATCH", "DELETE"],
path: str,
*,
params: dict[str, Any] | None = None,
json: dict[str, Any] | None = None,
content: bytes | None = None,
headers: dict[str, str] | None = None,
) -> Any
client.download(path: str) -> httpx.Response
request returns the JSON result member when present, the full payload otherwise, and None for HTTP 204. Both methods use the configured token and raise QualtricsAPIError for HTTP error responses.
The client keeps these flat methods as delegates to the service API. They accept the same arguments and defaults as the corresponding service methods:
| Compatibility method | Service equivalent |
|---|---|
list_surveys |
surveys.list |
iter_surveys |
surveys.iter |
get_survey |
surveys.get |
list_survey_quotas |
survey_quotas.list |
iter_survey_quotas |
survey_quotas.iter |
start_response_export |
response_exports.start |
get_response_export_progress |
response_exports.progress |
wait_for_response_export |
response_exports.wait |
download_response_export |
response_exports.download |
export_responses |
response_exports.export |
Errors¶
| Error | Meaning |
|---|---|
ValueError |
Invalid settings, a malformed input, or an invalid entity contract. Read the message for the missing field or conflict. |
FileNotFoundError |
Missing file, an unmatched wildcard, or a report destination whose parent does not exist. |
QualtricsAPIError |
Qualtrics returned an HTTP error. Inspect status_code and request_id. |
QualtricsExportError |
An import or export failed, timed out, or omitted a required job/file ID. |
httpx.HTTPError |
An HTTP transport failure, including timeouts. |
QualtricsAPIError and QualtricsExportError inherit from QualtricsError, a RuntimeError subclass. Import all three from qualtrics.api. See troubleshooting for recovery steps.