Get started

Website forms

Put a Kweko form on any website with one script tag, or post to the public form endpoint from your own form. Every submission becomes a lead with its UTM tags, without duplicate clients.

Embed with widget.js

Owners and admins build forms in Settings → Website forms. Each form has a public id (f…) and the page shows ready snippets:

Inline
<script src="https://your-workspace.kweko.uz/widget.js" data-kweko-form="fx7q2m…" async></script>
  • data-mode="popup" shows a button (data-button="Leave a request", or data-button="none") and opens the form in a dialog. Any link to #kweko-<form id>, any element with data-kweko-open="<form id>" and Kweko.open("<form id>") open it too.
  • data-target="#contact" renders an inline form into that element. data-lang="uz|ru|en" overrides the visitor's browser language; data-theme="dark|auto" switches colours.
  • The same script runs the web chat bubble: data-kweko-chat="<channel id>".
  • After a submission the page receives the kweko:form-submitted window event (event.detail.form).

The script is about 12 KB gzipped, renders in a closed Shadow DOM, uses no eval and no HTML strings, and never sends cookies. On a site with a Content-Security-Policy, allow your workspace address in script-src and connect-src. /widget.js is cached for five minutes (so fixes reach every site); /widget.js?v=<version> is immutable.

Forms also have a hosted page at https://your-workspace.kweko.uz/f/<form id> once the workspace is verified.

Post from your own form

The widget calls two public endpoints on your workspace address. They take no API key and no cookies; call them from the visitor's browser.

Load the form
curl "https://your-workspace.kweko.uz/api/forms/fx7q2m…?lang=ru"
Response
{ "id": "fx7q2m…", "lang": "ru", "title": "Оставьте заявку", "submit": "Отправить", "consent": "",
  "fields": [{ "id": "name", "type": "text", "label": "Имя", "required": true, "autocomplete": "name" },
             { "id": "phone", "type": "phone", "label": "Телефон", "required": true, "autocomplete": "tel" }],
  "color": "#c9420b", "token": "lx3k9a.Qm…", "min_ms": 3000 }
Submit
curl https://your-workspace.kweko.uz/api/forms/fx7q2m…/submit \
  -H "Content-Type: application/json" \
  -d '{"token": "lx3k9a.Qm…", "answers": {"name": "Dilnoza", "phone": "90 123 45 67"},
       "utm": {"utm_source": "instagram"}, "referrer": "https://instagram.com/", "landing_page": "https://shop.uz/sale", "lang": "ru"}'
Response (201)
{ "ok": true, "success": "Спасибо! Мы скоро свяжемся с вами.", "redirect_url": "" }
  • token comes from the config call. It proves when the form was loaded: submissions sent less than min_ms after loading, or with the hidden website field filled in, get the same 201 but are dropped. A missing, forged or day-old token returns 409 form_expired; load the config again.
  • answers are keyed by field id. Phones are normalized to +998… like everywhere in Kweko. Field errors come back as 422 validation_failed with fields keyed by field id, in the visitor's language (X-Kweko-Locale).
  • consent: true is required when the form has a consent text.

What a submission does

Kweko looks for the client by phone, then by email. A known client is reused; depending on the form, the submission is added to their open lead or opens a new one. A new lead lands in the form's pipeline and stage with its source webform, tags, owner rule, custom field answers, utm, referrer and landing_page (lead fields). The lead's timeline shows the answers.

Events: form.submitted for every submission, plus the usual lead.created and contact.created when records are new, so automations and webhooks see form leads like any other.

Protection and limits

LimitValue
Submissions per visitor IP10 per minute
Submissions per form2,000 per day, at most 60 in a burst
Request body32 KB, 40 answers, 5,000 characters per answer
Forms per workspace, submissions per monthBy plan (see Usage in Settings)

Over a rate limit the endpoint answers 429 rate_limited with Retry-After; over the plan's monthly submissions it answers 429 form_quota_reached (the admins are notified). Card numbers are refused. With allowed websites set on a form, only those origins (exact, or https://*.example.uz for subdomains) and your hosted page may load and submit it (403 origin_not_allowed); CORS never allows credentials. Paused or deleted forms return 404 form_unavailable.