splash.args is a table with incoming parameters. It contains
merged values from the orignal URL string (GET arguments) and
values sent using application/json POST request.

For example, if you passed ‘url’ argument to a script using HTTP API,
then splash.args.url contains this URL.

splash.args is the preferred way to pass parameters to Splash scripts.
An alternative way is to use string formatting to build a script with
variables embedded. There are two problems which make splash.args
a better solution:

data must be escaped somehow, so that it doesn’t break a Lua script;

embedding variables makes it impossible to use script cache efficiently
(see save_args and load_args
arguments of the HTTP API).

Private mode is enabled by default unless you pass flag --disable-private-mode at Splash startup.
Note that if you disable private mode browsing data such as cookies or items kept in local
storage may persist between requests.

By default, images are enabled. Disabling of the images can save a lot
of network traffic (usually around ~50%) and make rendering faster.
Note that this option can affect the JavaScript code inside page:
disabling of the images may change sizes and positions of DOM elements,
and scripts may read and use them.

Splash uses in-memory cache; cached images will be displayed
even when images are disabled. So if you load a page, then disable images,
then load a new page, then likely first page will display all images
and second page will display some images (the ones common with the first page).
Splash cache is shared between scripts executed in the same process, so you
can see some images even if they are disabled at the beginning of the script.

By default Splash doesn’t keep bodies of each response in memory,
for efficiency reasons. It means that in splash:on_response
callbacks response.body attribute is not available, and that
response content is not available in HAR exports. To make response content
available to a Lua script set splash.response_body_enabled=true.

baseurl - base URL to use, optional. When baseurl argument is passed
the page is still loaded from url, but it is rendered as if it was
loaded from baseurl: relative resource paths will be relative
to baseurl, and the browser will think baseurl is in address bar;

headers - a Lua table with HTTP headers to add/replace in the initial request.

http_method - optional, string with HTTP method to use when visiting url,
defaults to GET, Splash also supports POST.

body - optional, string with body for POST request

formdata - Lua table that will be converted to urlencoded POST body and sent
with header content-type:application/x-www-form-urlencoded

Returns:ok,reason pair. If ok is nil then error happened during
page load; reason provides an information about error type.

Async: yes, unless the navigation is locked.

Five types of errors are reported (ok can be nil in 5 cases):

There is a network error: a host doesn’t exist, server dropped connection,
etc. In this case reason is "network<code>". A list of possible
error codes can be found in Qt docs. For example, "network3" means
a DNS error (invalid hostname).

Server returned a response with 4xx or 5xx HTTP status code.
reason is "http<code>" in this case, i.e. for
HTTP 404 Not Found reason is "http404".

Splash can’t render the main page (e.g. because the first request was
aborted) - reason is render_error.

If Splash can’t decide what caused the error, just "error" is returned.

Error handling example:

localok,reason=splash:go("http://example.com")ifnotokthenifreason:sub(0,4)=='http'then-- handle HTTP errorselse-- handle other errorsendend-- process the page-- assert can be used as a shortcut for error handlingassert(splash:go("http://example.com"))

Errors (ok==nil) are only reported when “main” webpage request failed.
If a request to a related resource failed then no error is reported by
splash:go. To detect and handle such errors (e.g. broken image/js/css
links, ajax requests failed to load) use splash:har
or splash:on_response.

splash:go follows all HTTP redirects before returning the result,
but it doesn’t follow HTML <metahttp-equiv="refresh"...> redirects or
redirects initiated by JavaScript code. To give the webpage time to follow
those redirects use splash:wait.

headers argument allows to add or replace default HTTP headers for the
initial request. To set custom headers for all further requests
(including requests to related resources) use
splash:set_custom_headers or splash:on_request.

User-Agent header is special: once used, it is kept for further requests.
This is an implementation detail and it could change in future releases;
to set User-Agent header it is recommended to use
splash:set_user_agent method.

cancel_on_redirect - if true (not a default) and a redirect
happened while waiting, then splash:wait stops earlier and returns
nil,"redirect". Redirect could be initiated by
<metahttp-equiv="refresh"...> HTML tags or by JavaScript code.

cancel_on_error - if true (default) and an error which prevents page
from being rendered happened while waiting (e.g. an internal WebKit error
or a network error like a redirect to a non-resolvable host)
then splash:wait stops earlier and returns nil,"<errorstring>".

Returns:ok,reason pair. If ok is nil then the timer was
stopped prematurely, and reason contains a string with a reason.

By default wait timer continues to tick when redirect happens.
cancel_on_redirect option can be used to restart the timer after
each redirect. For example, here is a function that waits for a given
time after each page load in case of redirects:

Lua strings, numbers, booleans and tables can be passed as arguments;
they are converted to JS strings/numbers/booleans/objects.
Element instances are supported, but they can’t
be inside a Lua table.

Currently it is not possible to pass other Lua objects. For example, it
is not possible to pass a wrapped JavaScript function or a regular Lua function
as an argument to another wrapped JavaScript function.

By default Lua tables are converted to JavaScript Objects. To convert
a table to an Array use treat.as_array.

Function result is converted from JavaScript to Lua data type. Only simple
JS objects are supported. For example, returning a function or a
JQuery selector from a wrapped function won’t work.

Returning a Node (a reference to a DOM element) or NodeList instance
(result of document.querySelectorAll) works though, but only if Node
or NodeList is the only result - Nodes and NodeLists can’t be inside
other objects or arrays.

Note

The rule of thumb: if an argument or a return value can be serialized
via JSON, then it is fine. You can also return DOM Element or a NodeList,
but they can’t be inside other data structures.

Note that currently you can’t return JQuery $ results and
similar structures from JavaScript to Lua; to pass data you have to
extract their attributes of interest as plain strings/numbers/objects/arrays:

Function arguments and return values are passed by value. For example,
if you modify an argument from inside a JavaScript function then the caller
Lua code won’t see the changes, and if you return a global JS object and modify
it in Lua then object won’t be changed in webpage context. The exception is
Element which has some mutable fields.

If a JavaScript function throws an error, it is re-throwed as a Lua error.
To handle errors it is better to use JavaScript try/catch because some of the
information about the error can be lost in JavaScript → Lua conversion.

splash:evaljs is useful for evaluation of short JavaScript snippets
without defining a wrapper function. Example:

localtitle=splash:evaljs("document.title")

Don’t use splash:evaljs when the result is not needed - it is
inefficient and could lead to problems; use splash:runjs instead.
For example, the following innocent-looking code (using jQuery) will do
unnecessary work:

splash:evaljs("$(console.log('foo'));")

A gotcha is that to allow chaining jQuery $ function returns a huge object,
splash:evaljs tries to serialize it and convert to Lua,
which is a waste of resources. splash:runjs doesn’t have this problem.

If the code you’re evaluating needs arguments it is better to use
splash:jsfunc instead of splash:evaljs and string formatting.
Compare:

Run asynchronous JavaScript code in page context. The Lua script will
yield until the JavaScript code tells it to resume.

Signature:result,error=splash:wait_for_resume(snippet,timeout)

Parameters:

snippet - a string with a JavaScript source code to execute. This code
must include a function called main. The first argument to main
is an object that has the properties resume and error. resume
is a function which can be used to resume Lua execution. It takes an optional
argument which will be returned to Lua in the result.value return value.
error is a function which can be called with a required string value
that is returned in the error return value.

timeout - a number which determines (in seconds) how long to allow JavaScript
to execute before forceably returning control to Lua. Defaults to
zero, which disables the timeout.

Returns:result,error pair. When the execution is successful
result is a table. If the value returned by JavaScript is not
undefined, then the result table will contain a key value
that has the value passed to splash.resume(…). The result table also
contains any additional key/value pairs set by splash.set(…). In case of
timeout or JavaScript errors result is nil and error contains an
error message string.

Async: yes.

Examples:

The first, trivial example shows how to transfer control of execution from Lua
to JavaScript and then back to Lua. This command will tell JavaScript to
sleep for 3 seconds and then return to Lua. Note that this is an async
operation: the Lua event loop and the JavaScript event loop continue to run
during this 3 second pause, but Lua will not continue executing the current
function until JavaScript calls splash.resume().

result is set to an empty table to indicate that nothing was returned
from splash.resume. You can use assert(splash:wait_for_resume(…))
even when JavaScript does not return a value because the empty table signifies
success to assert().

Note

Your JavaScript code must contain a main() function. You will get an
error if you do not include it. The first argument to this function can
have any name you choose, of course. We will call it splash by
convention in this documentation.

The next example shows how to return a value from JavaScript to Lua.
You can return booleans, numbers, strings, arrays, or objects.

As with splash:evaljs, be wary of returning objects that are
too large, such as the $ object in jQuery, which will consume a lot
of time and memory to convert to a Lua result.

You can also set additional key/value pairs in JavaScript with the
splash.set(key,value) function. Key/value pairs will be included
in the result table returned to Lua. The following example demonstrates
this.

The next example shows an incorrect usage of splash:wait_for_resume():
the JavaScript code does not contain a main() function. result is
nil because splash.resume() is never called, and error contains
an error message explaining the mistake.

The next example shows the effect of the timeout argument. We have set
the timeout argument to 1 second, but our JavaScript code will not call
splash.resume() for 3 seconds, which guarantees that
splash:wait_for_resume() will time out.

When it times out, result will be nil, error will contain a string
explaining the timeout, and Lua will continue executing. Calling
splash.resume() or splash.error() after a timeout has no effect.

splash:call_later returns a handle (a timer). To cancel pending
task use its timer:cancel() method. If a callback is already
started timer:cancel() has no effect.

By default, exceptions raised in splash:call_later callback
stop the callback, but don’t stop the main script. To reraise these errors
use timer:reraise().

splash:call_later arranges callback to be executed in future;
it never runs it immediately, even if delay is 0. When delay is 0
callback is executed no earlier than current function yields to event loop,
i.e. no earlier than some of the async functions is called.

Nothing prevents us from taking multiple HTML snapshots. For example, let’s
visit first 3 pages on a website, and for each page store
initial HTML snapshot and an HTML snapshot after waiting 0.5s:

treat=require("treat")-- Given an url, this function returns a table-- with the page screenshoot, it's HTML contents-- and it's title.functionpage_info(splash,url)localok,msg=splash:go(url)ifnotokthenreturn{ok=false,reason=msg}endlocalres={html=splash:html(),title=splash:evaljs('document.title'),image=splash:png(),ok=true,}returnresend-- visit first 3 pages of hacker newslocalbase="https://news.ycombinator.com/news?p="functionmain(splash)localresult=treat.as_array({})fori=1,3dolocalurl=base..iresult[i]=page_info(splash,url)endreturnresultend

Returns: PNG screenshot data, as a binary object.
When the result is empty nil is returned.

Async: no.

Without arguments splash:png() will take a snapshot of the current viewport.

width parameter sets the width of the resulting image. If the viewport has a
different width, the image is scaled up or down to match the specified one.
For example, if the viewport is 1024px wide then splash:png{width=100} will
return a screenshot of the whole viewport, but the image will be downscaled to
100px width.

height parameter sets the height of the resulting image. If the viewport has
a different height, the image is trimmed or extended vertically to match the
specified one without resizing the content. The region created by such
extension is transparent.

To set the viewport size use splash:set_viewport_size,
splash:set_viewport_full or render_all argument. render_all=true
is equivalent to running splash:set_viewport_full() just before the
rendering and restoring the viewport size afterwards.

To render an arbitrary part of a page use region parameter. It should
be a table with {left,top,right,bottom} coordinates. Coordinates
are relative to current scroll position. Currently you can’t take anything
which is not in a viewport; to make sure part of a page can be rendered call
splash:set_viewport_full before using splash:png with region.
This may be fixed in future Splash versions.

With region and a bit of JavaScript it is possible to render only a single
HTML element. Example:

scale_method parameter must be either 'raster' or 'vector'. When
scale_method='raster', the image is resized per-pixel. When
scale_method='vector', the image is resized per-element during rendering.
Vector scaling is more performant and produces sharper images, however it may
cause rendering artifacts, so use it with caution.

The result of splash:png is a binary object,
so you can return it directly from “main” function and it will be sent as
a binary image data with a proper Content-Type header:

Returns: JPEG screenshot data, as a binary object.
When the image is empty nil is returned.

Async: no.

Without arguments splash:jpeg() will take a snapshot of the current viewport.

width parameter sets the width of the resulting image. If the viewport has a
different width, the image is scaled up or down to match the specified one.
For example, if the viewport is 1024px wide then splash:jpeg{width=100} will
return a screenshot of the whole viewport, but the image will be downscaled to
100px width.

height parameter sets the height of the resulting image. If the viewport has
a different height, the image is trimmed or extended vertically to match the
specified one without resizing the content. The region created by such
extension is white.

To set the viewport size use splash:set_viewport_size,
splash:set_viewport_full or render_all argument. render_all=true
is equivalent to running splash:set_viewport_full() just before the
rendering and restoring the viewport size afterwards.

To render an arbitrary part of a page use region parameter. It should
be a table with {left,top,right,bottom} coordinates. Coordinates
are relative to current scroll position. Currently you can’t take anything
which is not in a viewport; to make sure part of a page can be rendered call
splash:set_viewport_full before using splash:jpeg with region.
This may be fixed in future Splash versions.

With some JavaScript it is possible to render only a single HTML element
using region parameter. See an example
in splash:png docs. An alternative is to use element:jpeg.

scale_method parameter must be either 'raster' or 'vector'. When
scale_method='raster', the image is resized per-pixel. When
scale_method='vector', the image is resized per-element during rendering.
Vector scaling is more performant and produces sharper images, however it may
cause rendering artifacts, so use it with caution.

quality parameter must be an integer in range from 0 to 100.
Values above 95 should be avoided; quality=100 disables portions of
the JPEG compression algorithm, and results in large files with hardly any
gain in image quality.

The result of splash:jpeg is a binary object,
so you can return it directly from “main” function and it will be sent as
a binary image data with a proper Content-Type header:

Returns: information about pages loaded, events happened,
network requests sent and responses received in HAR format.

Async: no.

Use splash:har to get information about network requests and
other Splash activity.

If your script returns the result of splash:har() in a top-level
"har" key then Splash UI will give you a nice diagram with network
information (similar to “Network” tabs in Firefox or Chrome developer tools):

splash:init_cookies({{name="baz",value="egg"},{name="spam",value="egg",domain="example.com"},{name="foo",value="bar",path="/",domain="localhost",expires="2016-07-24T19:20:30+02:00",secure=true,httpOnly=true,}})-- do somethingassert(splash:go("http://example.com"))

Example 2, measure the time needed to build PNG screenshot and return it
result in an HTTP header:

functionmain(splash)-- this function measures the time code takes to execute and returns-- it in an HTTP headerfunctiontimeit(header_name,func)localstart_time=splash:get_perf_stats().walltimelocalresult=func()-- it won't work for multiple returned values!localend_time=splash:get_perf_stats().walltimesplash:set_result_header(header_name,tostring(end_time-start_time))returnresultend-- rendering scriptassert(splash:go(splash.args.url))localscreenshot=timeit("X-Render-Time",function()returnsplash:png()end)splash:set_result_content_type("image/png")returnscreenshotend

This will relayout all document elements and affect geometry variables, such
as window.innerWidth and window.innerHeight. However
window.onresize event callback will only be invoked during the next
asynchronous operation and splash:png is notably synchronous, so if
you have resized a page and want it to react accordingly before taking the
screenshot, use splash:wait.

Returns: two numbers: width and height the viewport is set to, in pixels.

Async: no.

splash:set_viewport_full should be called only after page is loaded, and
some time passed after that (use splash:wait). This is an unfortunate
restriction, but it seems that this is the only way to make automatic resizing
work reliably.

x - number with x position of element to be clicked
(distance from the left, relative to the current viewport)

y - number with y position of element to be clicked
(distance from the top, relative to the current viewport)

Returns: nil

Async: no.

Coordinates for mouse events must be relative to viewport.
Element on which action is performed must be inside viewport
(must be visible to the user). If element is outside viewport and
user needs to scroll to see it, you must either scroll to the element
with JavaScript or set viewport to full with
splash:set_viewport_full.

Mouse events are not propagated immediately, to see consequences of click
reflected in page source you must call splash:wait.

Returns:ok,result pair. If ok is not true then error
happened during the function call or the timeout expired; result
provides an information about error type. If result is equal to
timeout then the specified timeout period elapsed.
Otherwise, if ok is true then result contains the result of
the executed function. If your function returns several values, they
will be assigned to the next variables to result.

Async: yes.

Example 1:

functionmain(splash)localok,result=splash:with_timeout(function()localurl=splash.args.urlsplash:wait(3)assert(splash:go(url))end,2)ifnotokthenifresult=="timeout_over"thenreturn"Cannot navigate to the url within 2 seconds"elsereturnresultendendreturn"Navigated to the url within 2 seconds"end

Note that if the specified timeout period elapsed Splash will try to
interrupt the running function. However, Splash scripts are executed
in cooperative multitasking manner and because of that sometimes
Splash won’t be able to stop your running function upon timeout expiration.
In two words, cooperative multitasking means that the managing program
(in our example, it is Splash scripting engine) won’t stop the running
function if it doesn’t ask for that. In Splash scripting the running
function can be interrupted only if some async operation was called.
On the contrary, non of the sync operations can be interrupted.

functionmain(splash)localok,result=splash:with_timeout(function()splash:go(splash.args.url)-- during this operation the current function can be stoppedsplash:evaljs(long_js_operation)-- during JS function evaluation the function cannot be stoppedlocalpng=splash:png()-- sync operation and during it the function cannot be stoppedreturnpngend,0.1)returnresultend

We can’t always assume that a <Tab> will focus the input we want or an
<Enter> will submit a form. Selecting an input can either be accomplished
by focusing it or by clicking it. Submitting a form can also be done by
firing a submit event on the form, or simply by clicking on the submit button.

The following example will focus an input, fill in a form and click on the
submit button using splash:mouse_click. It assumes there are two
arguments passed to splash, username and password.

functionmain(splash)functionfocus(sel)splash:select(sel).node:focus()endassert(splash:go(splash.args.url))assert(splash:wait(0.5))focus('input[name=username]')splash:send_text(splash.args.username)assert(splash:wait(0))focus('input[name=password]')splash:send_text(splash.args.password)splash:select('input[type=submit]'):mouse_click()assert(splash:wait(0))-- Usually, wait for the submit request to finish-- ...end

Using splash:select you can get the element that matches your
specified CSS selector like using document.querySelector in the browser.
The returned element is an Element Object which has many useful
methods and almost all methods and attributes that element has in JavaScript.

If the element cannot be found using the specified selector nil will
be returned. If your selector is not a valid CSS selector an error will
be raised.

Example 1: select an element which has element class and return class
names off all the siblings of the specified element.