Code development workflow

Hi. Thanks to many of the examples in the forum I have some success in creating a widget. Scriptable is really really awesome!

So far I have been doing the coding and testing work on my iPad with an external keyboard. I am wondering how everyone writes and tests their code. Is it possible to write and test codes on a Linux or Windows machine and then copy the js files to the iOS devices when ready?

1 Like

If you install iCloud Drive on Windows you can sync the Scriptable folder containing the Scriptable code files.

Thanks. Yes I can do that. I am a newbie in JavaScript. I am wondering what dev tools I can use to write Javascript that is usable / supported by Scriptable? I tried Visual Studio Code and Node.js but even simple “Request” doesn’t work…

i mostly edit right inside Scriptable because it has the advantage of recognizing Scriptable libraries/objects for autocompletion and it is easier to test the scripts.

on rare occasions, i use vim on my Mac (opening Scriptable scripts via iCloud sync) or Textastic on iPad (via external folder).

APIs like Request and the new ListWidget is specific for Scriptable, hence you won’t be able to test any scripts using them unless inside Scriptable itself.

I’m maintaining a TypeScript definition file for exactly that purpose.

You can find more info here:

It only works for auto completion, not running your script in node.js.

I’m using VisualStudio Code on Windows. Since I needed quite a lot testing, iCloud drive sync wasn’t fast enough for me, so I used Git for Windows to push the script to a private Gist and used a script to download it on iOS:

One caveat: The script cannot download files into folders, only directly into the documents folder of Scriptable as far as I know. And it has to be run after you’ve pushed with Git otherwise you see an old version.


This is fascinating, thanks for posting. I’ve been trying to find the right solution for syncing as iCloud can be really unstable, especially when syncing the same file between 2 devices (I made a time tracker that uses a txt file as datastore, and have accidentally wiped the day’s data when using on iPad & iPhone). I’ll think about your GitHub download option and see if it makes sense for me.

On the main topic, I recently completed a setup similar to @schl3ck:

  • TypeScript repo w/ a custom Scriptable .d.ts file for proper typing of Scriptable APIs
  • Rollup.js to compile TS to JS directly into Scriptable documents folder.
    • I also use this to combine and minify files – this was a big improvement in my setup, as I used to use importModule extensively and found that often the imported files weren’t yet downloaded, causing the script to fail. Now everything’s compiled into a single package, so it’s either all there or none of it is.
    • Another cool side effect of rollup is the graph plugin – every time I compile, it updates a .dot file with a dependency graph of all my files.

This new setup has seriously been a game changer for my workflow – files don’t compile if there are type errors, so it’s much rare for me to get broken scripts now. Having typings for all the Scriptable APIs is really convenient, and I’m able to really break down my files into granular components without worrying about the iCloud issues.

I’d like to write a post about this at some point, it’s just tough to find the time. Happy to share more details/my config & type files if requested.

Edit: lol nvm, your typing is waaay cleaner than mine, nice work getting all the text documentation in as comments as well. In reading through I saw the up-to-date JSON version of docs that Simon shared, bookmarked that for later.

Edit 2: I finally published my setup:


I also publish the types to npm with DefinitivelyTyped, but they are currently taking ages to accept the pull request with the new 1.5 types :disappointed: You can find the types at

And whenever @simonbs releases a new version I update them as quickly as possible together with checking on typos made by him.


Double post, but just wanted to let you all know that the new Scriptable types for version 1.5.1 are published on npm!


npm stills says it’s version 1.5.0.

Yes, because it is the first publish with 1.5 and I can only specify the major and minor version. The patch version is the count of publishes which I can’t specify.

The published typings are for Scriptable 1.5.1


this is awesome! can someone give me a quick rundown or link on how I’d set this up inside VSCode? (on Mac, if it matters…)

1 Like

Does this help you?


Thanks. Really good stuff!

In Visual Code, I followed the instructions and ran

npm install --save @types/scriptable-ios

And then edited the two json files as shown at

Thank you very much. This has saved my neck (literally… ergonomically-wise). Cheers.

1 Like

Hey @jsloat it would be great to see your config with rollup.js. It sounds very great.

I made this for me:

I can now edit code in my favorite editor, push changes to gitlab and the code is automatically updated on the iPhone.

The Scriptable-script itself is just a few lines of simple code which downloads the real functionality in a library file from GitLab to the iPhone.

This way, code can also be versioned and updated for existing users of the script without them having to copy&paste the updated code to their iPhone.

I have to add that I cannot use the iCloud-sync because I’m on a company’s MacBook with restrictive policies enforced (no login to iCloud-Account).


I was really inspired by your setup @Sillium and decided to expand a bit on it.

I just created a boilerplate to make it easy to write, compile and serve auto-updatable widgets with Nextjs.

Besides making the local development more comfortable, this also enables you to share widgets to others that are automatically updated if a new version is deployed. Great for prototyping actual products.

@PascalBru this boilerplate also has a rollup.js config that seems to work nicely.

I do have one issue though. Hope someone can help.

Somehow the widgets sometimes interfere with each other resulting in the error: Call Script.setWidget() to set content of the widget. This doesn’t happen if I only have 1 instance of a widget, some more background here: .

The repo is still missing some details in the README, but I hope this is already useful to someone!

1 Like

I’ve fixed my issue of widgets interfering with each other.

It seems to happen if you use callbacks instead of top-level await for async methods. Not sure if this is a known issue? Couldn’t find this requirement anywhere in the documentation @simonbs .