Webscript Documentation

Getting Started

Webscript's Lua environment includes library functions for accessing commonly needed facilities like HTTP routines and persistent storage. In addition, it presents a convenient convention for returning script results to an HTTP request.

Scripts are written in Lua version 5.1.5. If you are new to Lua, we recommend first reading our Lua tutorial: Lua in Relatively Few Words

Script Structure

Webscripts are a sequence of executable Lua statements, implicitly wrapped in a function, and ending with a return statement. There is no "main” function—execution begins with the first statement and proceeds on.

Values Passed to the Script

Webscript passes a global table to your script called request. This parameter contains the originating HTTP request with the following fields:

  • form – A table consisting of form data posted to your script. This field is only present if the request has a Content-Type of multipart/form-data or application/x-www-form-urlencode and the body is successfully parsed as form-encoded.
  • query – A table consisting of query string parameters from the request's URL. For example, the query string ?color=red&number=3 will result in a query table of {color="red", number="3"}.
  • querystring – The raw query string from the URL. Using the previous example, the querystring value would be "color=red&number=3".
  • files – A table consisting of files included in a form post. For each included file, the key is the name of the form's input field, and the value is a table consisting of type (the content-type of the uploaded file), filename (original file name), and content (the raw contents of the file).
  • body – The content of the request, after it's been decoded as needed (e.g. decompressed as specified by a Content-Encoding header).
  • method – The HTTP request method. (E.g., GET, POST, ...)
  • remote_addr – The request's origin IP address.
  • scheme – The URL scheme. (E.g., http or https.)
  • port – The URL's port. (E.g., 80 or 443.)
  • path – The URL's path. (E.g., for the URL http://example.webscript.io/foo/bar, the path is /foo/bar.)
  • headers – A table of the HTTP request headers. Keys are "train-cased," like Content-Type.

Note: To support Internet Explorer's cross-domain requests using XDomainRequest, if a request has no Content-Type header, an attempt is still made to parse it as application/x-www-form-urlencode.

Return Values

Webscript interprets the return value of a script as a response to the HTTP request. A script may return zero or more return values, which are interpreted as follows:

  • Return a string to set the body of the response. Note that Lua strings can contain arbitrary binary data.
  • Return an integer to set the status code.
  • Return a table to send JSON or set the response headers:
    • If no string is returned, the first table returned is sent as JSON, with a Content-Type header of application/json.
    • Any other table is interpreted as HTTP response headers.

The default status code is 200, and the default Content-Type is text/plain.

A few examples:

return "Success!"

return 200

return 403, "Not allowed."

return "<h1>Hello, World!</h1>", {["Content-Type"]="text/html"}

return {color="red", number=3}

return {color="red", number=3}, {["Cache-Control"]="no-cache"}

Persistent Storage

Webscript provides persistent storage—storage that exists between script invocations. The persistent storage is accessed via the storage table.

Storage is scoped to a single subdomain (e.g., example.webscript.io) but is shared amongst all scripts under that subdomain.

A simple storage example that remembers the last user to call the script:

storage.lastuser = request.form.username

That value could be accessed on subsequent calls to any script under the same subdomain as storage.lastuser. All values in persistent storage are strings. Implicit casts are performed on assignment.

Accessing a non-existent storage key returns nil, and assigning nil to a key deletes that key.

Making Outbound HTTP Requests

Scripts can easily make outgoing HTTP requests by calling the built-in http.request function. This function takes one parameter, a table with the following fields:

  • url – The target URL, including scheme, e.g. http://example.com
  • method (optional, default is "GET") – The HTTP verb, e.g. GET or POST
  • data (optional) – Either a string (the raw bytes of the request body) or a table (converted to form POST parameters)
  • params (optional) – A table that's converted into query string parameters. E.g. {color="red"} becomes ?color=red
  • auth (optional) – Two possibilities:
    • auth={'username', 'password'} means to use HTTP basic authentication
    • auth={oauth={consumertoken='...', consumersecret='...', accesstoken='...', tokensecret='...'}} means to sign the request with OAuth. Only consumertoken and consumersecret are required (e.g. for obtaining a request token)
  • headers (optional) – A table of the request header key/value pairs

A call to http.request returns a table with the following fields:

  • content – The raw bytes of the HTTP response body, after being decoded if necessary according to the response's Content-Encoding header.
  • statuscode – The numeric status code of the HTTP response
  • headers – A table of the response's headers

The function http.qsencode can be used to convert a table of key/value pairs into a query string. This function is rarely needed because the params field can be used to the same effect when making an HTTP request.

The function http.qsparse can be used to convert a query string into a table of key/value pairs. This function is rarely needed because request.query already contains the parsed query string for an incoming request.

Sending Email

Scripts can send email using the email.send function. This function takes one parameter, a table with the following fields:

  • server – The SMTP server's full domain
  • username – The SMTP username
  • password – The SMTP password
  • from – The sender's email address
  • to – The recipient's email address. Multiple recipients can be specified with a table, e.g. {'someone@example.com', 'someone_else@example.com'}.
  • subject – The subject of the email
  • text (optional) – The email body in text format. At least one of text and html must be specified.
  • html (optional) – The email body in HTML format. At least one of text and html must be specified.
  • attachments (optional) – Any file attachments to be included with the email. See below for details about this parameter.
  • replyto (optional) – The reply-to address. Note that not all email providers will respect this field.
  • secure (optional, defaults to true) – Whether or not to use TLS to connect to the SMTP server

The attachments field, if present, should be an array-style table, where each member is itself a table with the following fields:

  • filename – The name of the attachment.
  • content – The contents of the attachment (a Lua string).
  • type (optional) – The content type for the attachment (e.g. image/jpeg). The default is application/octet-stream.

Example: attachments = { { filename = 'hello.txt', content = 'Hello, World!', type = 'text/plain' }, ... }

Generating and Parsing JSON

Webscript includes two JSON functions:

  • json.parse(str) – Convert a JSON-encoded string into a Lua table.
  • json.stringify(T) – Convert a Lua table into a JSON-encoded string.

Cryptographic Functions

Webscript includes the following basic cryptography functions:

  • crypto.bcrypt.hash(str) or crypto.bcrypt.hash { password=str, rounds=n } – Hash a password using the bcrypt algorithm. The default number of rounds is 12.
  • crypto.md5(str).digest() or crypto.md5(str).hexdigest() – Hash a string using the MD5 algorithm and return the hash as either raw bytes or a hexadecimal-encoded string.
  • crypto.sha1(str).digest() or crypto.md5(str).hexdigest() – Hash a string using the SHA1 algorithm and return the hash as either raw bytes or a hexadecimal-encoded string.
  • crypto.sha256(str).digest() or crypto.md5(str).hexdigest() – Hash a string using the SHA256 algorithm and return the hash as either raw bytes or a hexadecimal-encoded string.
  • crypto.hmac(key, str, hasher).digest() or crypto.hmac(key, str, hasher).hexdigest() – Create an HMAC signature using the specified hasher (crypto.md5, crypto.sha1, or crypto.sha256) and return the raw or hexadecimal-encoded HMAC.

Base64 Encoding

Webscript supports base64 encoding with the following functions:

  • base64.encode(str) – Produce the base64 encoding of the string str. Note that Lua strings can contain arbitrary binary data.
  • base64.decode(str) – Produce the string represented by the base64-encoded string str.


Webscript provides leases to enable scripts to ensure exclusive access to resources. The following functions are defined:

  • lease.acquire(str) – Acquire the lease named str. This call blocks until the lease becomes available and is acquired.
  • lease.release(str) – Release the lease named str.

Leases are scoped to a subdomain. All acquired leases are released when a script terminates.


Webscript maintains per-script logs. Scripts can write to the log using the log function:

  • log(str)


Scripts can send alerts to their owner by email or by SMS. Email alerts are sent from subdomain@script-alerts.webscript.io (using the subdomain of the script that sent the alert) and go to the email address of the Webscript user account. SMS messages are sent from the number +1 (425) 296-8394 and go to the phone number a user has verified on the settings page.

Note that alerts are only available for paid accounts and are limited to 1,000 email alerts and 100 SMS alerts per calendar month.

Alerts can be sent with the following functions:

  • alert.sms(str)
  • alert.email(str)
  • alert.email(table) – takes the subject, text, html, and attachments parameters as in email.send.

Including Modules From GitHub

To make a public GitHub repository available to webscripts, the repository owner must add https://www.webscript.io/github-hook as a post-receive webhook for the repository. (See https://help.github.com/articles/post-receive-hooks for GitHub webhook details.)

To import code from GitHub, use the require function:

  • <variable> = require('<github user>/<repository>/<filename.lua>')

For examples of how modules should work, see https://github.com/webscriptio/lib for the modules maintained by the Webscript team. These modules can be required without a full path. (E.g. local twilio = require 'twilio'.)

API Beta

Webscript supports a simple HTTP-based API for reading and writing scripts. The API is currently in beta with the version number 0.1 and is subject to change.


All access to the Webscript API uses HTTPS with basic authentication. The username should be the email address with which the user logs in to Webscript. The password should be the user's API key, which can be seen on the settings page.


All operations return responses in JSON format. The base URL for all operations is https://www.webscript.io/api/0.1.

Operation HTTP Verb URL Description
List subdomains GET /api/0.1/subdomains Returns a dictionary of subdomains. Example response:
 "demo-krbnjo": {
   "expired": false,
   "scripts": [
Get subdomain GET /api/0.1/subdomain/<subdomain>
(e.g. /api/0.1/subdomain/examples)
Returns the details of a single subdomain. Example response:
 "expired": false,
 "scripts": [
Get script GET /api/0.1/script/<subdomain>/<path>
(e.g. /api/0.1/script/examples/email)
Returns the code from a single script.
Save script PUT or POST /api/0.1/script/<subdomain>/<path>
(e.g. /api/0.1/script/examples/email)
Create or overwrite a script with new code. The code should be contained in the body of the HTTP request.
Delete script DELETE /api/0.1/script/<subdomain>/<path>
(e.g. /api/0.1/script/examples/email)
Delete a script.
Delete subdomain DELETE /api/0.1/subdomain/<subdomain>
(e.g. /api/0.1/subdomain/examples)
Delete an entire subdomain.
Get request logs GET /api/0.1/logs/<subdomain>/<path>
(e.g. /api/0.1/logs/examples/hello)
Retrieve a script's 20 most recent log entries in reverse chronological order as a JSON array. Each element of the array will be a hash containing timestamp, request, messages, and response members. Example response:
   "timestamp": "2012-12-05T16:42:27.656081+00:00",
   "request": {
     "url": "examples.webscript.io/hello",
     "headers": {
       "X-Forwarded-Port": "80",
       "X-Forwarded-For": "",
       "Connection": "close",
       "Accept": "*/*",
       "User-Agent": "curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5",
       "Host": "examples.webscript.io",
       "X-Forwarded-Proto": "http"
     "method": "GET"
   "messages": ["This is a log message."],
   "response": {
     "body": "Hello, World!",
     "status_code": 200,
     "headers": {
       "Content-Length": 13,
       "Content-Type": "text/plain",
       "Access-Control-Allow-Origin": "*",
       "Cache-Control": "no-store"