Skip to content
noBSredir

Surveys

Attach a one-question survey to any link. Visitors see the question before redirecting, tap an answer, and land on the destination. Responses are recorded with country, device, and referrer data. No Javascript involved - the survey page is pure HTML that loads instantly.

Plan: Available on all plans, including Free.

PlanSurveysResponses/month
Free150
ProUnlimited1,000
TeamUnlimited10,000
AgencyUnlimited100,000

When the monthly response limit is reached, surveys stop appearing on redirects until the next billing cycle. Existing responses are kept.

All survey endpoints are scoped to a link:

/api/workspaces/:wsId/links/:linkId/survey

PUT /workspaces/:wsId/links/:linkId/survey

Create or update a survey on a link. If the link already has a survey, it gets updated. If not, a new one is created.

Role: editor+

Terminal window
curl -X PUT https://nobsredir.com/api/workspaces/ws_abc123/links/lnk_xyz789/survey \
-H "X-API-Key: nobs_your_key" \
-H "Content-Type: application/json" \
-d '{
"question": "How did you find this?",
"options": ["Social", "Email", "Search", "Friend"],
"show_once": true,
"style": {
"bg_color": "#1a1a2e",
"text_color": "#e5e5e5",
"button_color": "#3b82f6"
}
}'

Body:

FieldTypeRequiredDescription
questionstringyesThe question to ask. 1-200 characters.
optionsstring[]yes2-4 answer options. Each 1-50 characters.
show_oncebooleannoOnly show the survey once per visitor via cookie. Default: true.
styleobjectnoCustom colors for the survey card. See Styling below.

Response 201 (created) or 200 (updated):

{
"survey": {
"id": "srv_a1b2c3d4e5f6",
"question": "How did you find this?",
"options": ["Social", "Email", "Search", "Friend"],
"active": true,
"show_once": true,
"style": {
"bg_color": "#1a1a2e",
"text_color": "#e5e5e5",
"button_color": "#3b82f6"
},
"created_at": "2026-03-07T10:00:00.000Z",
"updated_at": "2026-03-07T10:00:00.000Z"
}
}

Errors:

  • 400 - Missing or invalid question, wrong number of options (need 2-4), option too long, empty option
  • 402 - Survey limit reached for your plan, or surveys require a Pro plan
  • 404 - Link not found or doesn’t belong to this workspace

GET /workspaces/:wsId/links/:linkId/survey

Get the survey configuration for a link, including total response count.

Role: viewer+

Terminal window
curl https://nobsredir.com/api/workspaces/ws_abc123/links/lnk_xyz789/survey \
-H "X-API-Key: nobs_your_key"

Response 200 (survey exists):

{
"survey": {
"id": "srv_a1b2c3d4e5f6",
"question": "How did you find this?",
"options": ["Social", "Email", "Search", "Friend"],
"active": true,
"show_once": true,
"style": {
"bg_color": "#1a1a2e",
"text_color": "#e5e5e5",
"button_color": "#3b82f6"
},
"total_responses": 342,
"created_at": "2026-03-07T10:00:00.000Z",
"updated_at": "2026-03-07T10:00:00.000Z"
}
}

Response 200 (no survey):

{
"survey": null
}

Errors: 404 - Link not found.


DELETE /workspaces/:wsId/links/:linkId/survey

Delete the survey from a link. This permanently removes the survey configuration and all recorded responses. The link reverts to a normal redirect.

Role: editor+

Terminal window
curl -X DELETE https://nobsredir.com/api/workspaces/ws_abc123/links/lnk_xyz789/survey \
-H "X-API-Key: nobs_your_key"

Response 200:

{
"ok": true
}

Errors:

  • 404 - Link not found, or no survey exists on this link

GET /workspaces/:wsId/links/:linkId/survey/results

Get aggregated survey results with breakdowns by option, country, device, and day.

Role: viewer+

Terminal window
curl "https://nobsredir.com/api/workspaces/ws_abc123/links/lnk_xyz789/survey/results?days=30" \
-H "X-API-Key: nobs_your_key"

Query params:

ParamTypeDefaultDescription
daysinteger30Number of days to look back

Response 200:

{
"question": "How did you find this?",
"total_responses": 342,
"options": [
{ "index": 0, "label": "Social", "count": 145, "percent": 42.4 },
{ "index": 1, "label": "Email", "count": 98, "percent": 28.7 },
{ "index": 2, "label": "Search", "count": 67, "percent": 19.6 },
{ "index": 3, "label": "Friend", "count": 32, "percent": 9.4 }
],
"by_country": {
"US": { "total": 180, "options": [80, 50, 30, 20] },
"GB": { "total": 45, "options": [20, 12, 8, 5] }
},
"by_device": {
"mobile": { "total": 210, "options": [90, 60, 40, 20] },
"desktop": { "total": 132, "options": [55, 38, 27, 12] }
},
"by_referrer": {
"twitter.com": { "total": 85, "options": [35, 25, 15, 10] },
"google.com": { "total": 60, "options": [20, 18, 12, 10] }
},
"daily": [
{ "date": "2026-03-01", "total": 28, "options": [12, 8, 5, 3] },
{ "date": "2026-03-02", "total": 35, "options": [15, 10, 7, 3] }
]
}

Response fields:

FieldDescription
options[].indexPosition in the options array (0-based)
options[].percentPercentage of total responses, rounded to one decimal
by_countryKeyed by ISO country code. options array matches the option order.
by_deviceKeyed by device type (mobile, desktop, tablet).
by_referrerKeyed by referrer domain. Only includes responses with a referrer.
dailyOne entry per day with responses. options array matches the option order.

Errors:

  • 404 - Link not found, or no survey exists on this link

Styling

Customize the survey card colors to match your brand. All colors must be 6-digit hex values (e.g. #1a1a2e). Omitted properties use the default dark theme.

PropertyDefaultDescription
bg_color#0a0a0aPage background and option button background
text_color#e5e5e5Question text and option text color
button_color#3b82f6Option border highlights and hover accent
{
"style": {
"bg_color": "#1a1a2e",
"text_color": "#ffffff",
"button_color": "#e94560"
}
}

Only bg_color, text_color, and button_color are accepted. Unknown keys are silently ignored. Invalid hex values return a 400 error.

The card background is automatically derived from bg_color (slightly lighter) so you only need to set one background color.


How the redirect flow works

When a link has an active survey, the redirect adds one step between the click and the destination:

Click -> Expiry check -> Click limit -> Password -> Survey -> Redirect

The survey step:

  1. If the visitor already answered (cookie) and show_once is enabled, skip the survey
  2. If the visitor is a social media bot, skip the survey
  3. Otherwise, show the survey page (no Javascript, loads instantly)
  4. Visitor clicks an answer or skip
  5. Response is recorded, cookie is set, visitor gets a 302 redirect

The click is tracked when the answer is submitted, not when the survey page loads. Survey page views don’t inflate click counts. The response is recorded in the background - the redirect fires immediately with zero added latency.


Javascript example

Create a link with a survey, wait for responses, then pull results:

const API = "https://nobsredir.com/api";
const headers = {
"X-API-Key": "nobs_your_key",
"Content-Type": "application/json"
};
// 1. Create a link
const linkRes = await fetch(`${API}/workspaces/ws_abc123/links`, {
method: "POST",
headers,
body: JSON.stringify({
target: "https://yoursite.com/pricing",
domain: "go.yourco.com",
slug: "pricing",
}),
});
const link = await linkRes.json();
// 2. Attach a survey
await fetch(`${API}/workspaces/ws_abc123/links/${link.id}/survey`, {
method: "PUT",
headers,
body: JSON.stringify({
question: "Which plan interests you?",
options: ["Starter", "Pro", "Enterprise"],
show_once: true,
}),
});
// 3. Later - pull results
const results = await fetch(
`${API}/workspaces/ws_abc123/links/${link.id}/survey/results?days=7`,
{ headers }
);
const data = await results.json();
console.log(`${data.total_responses} responses in 7 days`);
for (const opt of data.options) {
console.log(` ${opt.label}: ${opt.count} (${opt.percent}%)`);
}

Python example

import requests
API = "https://nobsredir.com/api"
HEADERS = {"X-API-Key": "nobs_your_key"}
WS = "ws_abc123"
# Create a link
link = requests.post(f"{API}/workspaces/{WS}/links", headers=HEADERS, json={
"target": "https://yoursite.com/blog",
"domain": "go.yourco.com",
"slug": "blog",
}).json()
# Attach a survey
requests.put(
f"{API}/workspaces/{WS}/links/{link['id']}/survey",
headers=HEADERS,
json={
"question": "Was this article helpful?",
"options": ["Yes", "No"],
"show_once": True,
},
)
# Pull results
results = requests.get(
f"{API}/workspaces/{WS}/links/{link['id']}/survey/results",
headers=HEADERS,
params={"days": 30},
).json()
print(f"{results['total_responses']} responses")
for opt in results["options"]:
print(f" {opt['label']}: {opt['count']} ({opt['percent']}%)")

MCP tools

If you’re using the MCP server, four survey tools are available:

ToolDescription
create_surveyCreate or update a survey on a link
get_surveyGet survey config and response count
get_survey_resultsPull aggregated results with breakdowns
delete_surveyRemove a survey and all responses

These map directly to the API endpoints above.