Skip to main content

SFTP v1.0.0

On visitor action (such as click on a button, scoring, input...) Screeb can upload a JSON file to an external SFTP server containing the response data.

Entitiesโ€‹

  • Organization: A Screeb account, shared by many Screeb users of your company
  • Channel: A distribution channel for your survey (Javascript SDK, Android SDK, iOS SDK...)
  • Survey
  • Survey scenario: A versioned survey: on survey update, your flow is saved in a new scenario. New users will see the last scenario.
  • User: Information about the visitor
  • Response: A response is a chain of question+answers. A user sometimes has many responses to a single survey.
  • Question
  • Answer: An answer is part of a response. Each answer is associated with a question.
  • Field: An answer may have many fields (eg: multiple choices question)

Hook typesโ€‹

You can trigger SFTP uploads on 3 different events:

  • On survey display: a survey is shown to visitors, but no question is replied. You will get notified even if no response is given.
  • On question answered: a question has been replied. This webhook will be triggered for each question of a single survey.
  • On response end: a survey has been closed or fully replied to by the user.

Configurationโ€‹

To configure your SFTP integration, you need to provide:

  • Host: The SFTP server hostname or IP address
  • Port: The SFTP connection port. If empty, Screeb uses 22.
  • Username: Your SFTP account username
  • Authentication: Either a password, or an SSH key generated by Screeb (see below). Exactly one of the two is required.
  • Path: Optional base directory on the SFTP server. If provided, Screeb trims leading and trailing slashes and appends its own folder structure below it.

Authenticationโ€‹

Two authentication methods are supported:

  • Username and password: the traditional method, unchanged.
  • Username and SSH key: from the integration settings, generate a key pair. Screeb creates an ed25519 key pair on its servers and returns the public key for you to install in the authorized_keys file of the corresponding user on your SFTP server. The private key is stored server-side and is never returned by the API again; there is no way to download or display it after generation.

Host key pinningโ€‹

The integration settings screen has a Test connection button that validates the host, port, username, and credentials against your server. On a successful test, Screeb captures your server's host key and pins its OpenSSH SHA256 fingerprint (SHA256:...) to the integration once you save it. From then on, every export verifies the server presents that same host key and fails if it does not, protecting against a compromised or spoofed server after the initial setup. Integrations set up before this pinning feature keep working without a pinned fingerprint until you run Test connection and save.

If you have configured a base path, running Test connection creates that directory on your server if it does not already exist: it is not a purely read-only check.

Network accessโ€‹

If your SFTP server restricts inbound connections by IP, whitelist Screeb's egress IP addresses on your firewall. The current list is shown on the integration settings screen and depends on your Screeb environment.

Remote file structureโ€‹

Screeb always uploads JSON files in a deterministic directory layout:

  • Survey display events: /workspaces/<workspace_id>/surveys/<survey_id>/displays/<response_id>.json
  • Question answered events: /workspaces/<workspace_id>/surveys/<survey_id>/responses/<response_id>.json
  • Response ended events: /workspaces/<workspace_id>/surveys/<survey_id>/responses/<response_id>.json

If you configure a custom base path, it is prepended to the structure above. For example:

  • Configured path: /exports/screeb
  • Final upload path: /exports/screeb/workspaces/<workspace_id>/surveys/<survey_id>/responses/<response_id>.json

Because response.answered and response.ended use the same destination path for a given response, later uploads replace the previous file for that response.

Uploads are atomic: Screeb writes the file under a temporary name and renames it into its final path only once the write is complete. A process polling the directory never sees a partially written file; it either finds the previous version or the complete new one.

Payload formatโ€‹

The SFTP integration uploads survey data in JSON format. The filename is the response identifier:

<response_id>.json

Payload structureโ€‹

{
"event_id": "64c7ea3b-827b-4679-b25d-7fd61f6c3d33",
"event_type": "response.ended",
"version": "1.0.0",
"time": "2021-07-29T13:45:09.325344042Z",
"time_ms": 1627566309325,
"payload": {
"organization": {
"id": "b5969d13-5e5e-4648-9806-5339ddafd984",
"name": "ACME"
},
"channel": {
"id": "411ee7c3-7e64-409f-9d75-c782b3f73aa4",
"type": "android"
},
"survey": {
"id": "9b913c69-3daf-4a6e-a26d-042004fc7881",
"name": "Measure NPS",
"scenario_id": "cc4a3710-e8ee-4672-a35c-5c17485ec441",
"scenario_version": 9,
"scenario_time": "2021-07-29T00:08:31.069497Z",
"scenario_time_ms": 1627517311069
},
"user": {
"anonymous_id": "2eb83fb4-b1b3-4e48-be48-a8fd9c4e5a7d",
"user_id": "support@screeb.app",
"name": "John Doe",
"email": "support@screeb.app",
"group_names": ["Screeb", "10-100-companies", "plan-enterprise"],
"properties": {
"firstname": "John",
"lastname": "Doe",
"email": "support@screeb.app",
"plan": "free"
}
},
"response": {
"id": "5854a797-628c-4906-bb4c-da03e418cf47",
"locale": "en-US",
"time": "2021-07-29T13:44:59.831Z",
"time_ms": 1627918228831,
"time_to_complete_second": 34,
"completion": "fully_completed",
"hidden_fields": {
"variable-from-crm": "blablabla"
},
"context": {
"active_page": {
"url": "https://screeb.app/solutions/product-analytics?utm_medium=email"
},
"locale": "en-GB"
},
"question": {
"id": "a44252c3-ef3d-4156-90d6-a3d6364516c0",
"correlation_id": "c6d4d007-879f-43fe-b4cf-d58e1f8ed1f8",
"type": "input",
"title": "How can we improve your experience?"
},
"answer": {
"field": {
"id": "c71dfe9d-6b47-452f-bda2-6091c13561b0",
"correlation_id": "eb398cc0-1223-4590-bb60-e41ac8dfb0f6",
"type": "string",
"value": "The new dashboard is buggy.",
"text": "The new dashboard is buggy."
},
"fields": [
{
"id": "c71dfe9d-6b47-452f-bda2-6091c13561b0",
"correlation_id": "eb398cc0-1223-4590-bb60-e41ac8dfb0f6",
"type": "string",
"value": "The new dashboard is buggy.",
"text": "The new dashboard is buggy."
}
],
"replied_at": "2021-07-29T13:45:09.286Z",
"replied_at_ms": 1627566309286,
"tags": ["screeb", "feedback"]
},
"tags": ["screeb", "feedback"],
"items": [
{
"question": {
"id": "a44252c3-ef3d-4156-90d6-a3d6364516c0",
"correlation_id": "c6d4d007-879f-43fe-b4cf-d58e1f8ed1f8",
"type": "input",
"title": "How can we improve your experience?"
},
"answer": {
"fields": []
}
}
]
}
}
}

Payload notesโ€‹

  • The top-level JSON contains event_id, event_type, version, time, time_ms, and payload.
  • payload.user.properties, payload.response.context, and payload.response.hidden_fields are free-form nested objects.
  • payload.response.question and payload.response.answer are mainly useful for response.answered events.
  • payload.response.items contains the ordered list of answered questions available at the time the file is generated.
  • payload.response.answer.field is kept for backward compatibility, while payload.response.answer.fields is the complete list.
  • Question and answer fields include both id and correlation_id.

Event-specific behaviorโ€‹

  • response.displayed uploads to the displays folder and uses the response creation time as event time.
  • response.answered uploads to the responses folder and includes question, answer, items, tags, and a computed completion status.
  • response.ended uploads to the responses folder and includes the final items, tags, completion, and time_to_complete_second.

Best practicesโ€‹

  1. Use a dedicated SFTP directory for Screeb exports.
  2. Expect files to be overwritten for the same response in the responses folder.
  3. Restrict the SFTP account to write access on the export directory only.
  4. Consume files by parsing JSON content rather than relying on filename patterns.
  5. If needed, archive files after ingestion on your side.
  6. Prefer SSH key authentication over a password, and run Test connection to pin the server's host key fingerprint once your server is reachable.

Troubleshootingโ€‹

Connection failedโ€‹

  • Verify that the SFTP server is reachable
  • Check firewall rules allow outbound connections to the SFTP port
  • Verify credentials are correct

Authentication errorโ€‹

  • Ensure username and password are correct, or that the installed SSH public key matches the key pair generated for this integration
  • Check if the SFTP account has the necessary permissions
  • Check that the public key is present in the correct user's authorized_keys file on the server

Host key mismatchโ€‹

  • This means the server's host key no longer matches the fingerprint pinned when you last ran Test connection. This can happen after a legitimate server migration or key rotation, or it can indicate the connection is being intercepted.
  • Confirm with your infrastructure team that the server's host key changed for a legitimate reason before proceeding.
  • Once confirmed, run Test connection again and save the integration to pin the new fingerprint.

Upload failedโ€‹

  • Verify the remote path exists and the account has write permissions
  • Check available disk space on the SFTP server

Compatibility notesโ€‹

  • Authentication supports username/password or username/SSH key.
  • If no port is configured, Screeb connects on port 22.
  • Screeb creates missing directories automatically before uploading the file.
  • Host key pinning is opt-in: integrations without a pinned fingerprint keep the previous behavior of accepting the server's key without verification. Run Test connection and save to start pinning.

Supportโ€‹

For additional help with your SFTP integration, please contact our support team or refer to the main API documentation.