This article is the fourth in a series exploring fun, straightforward ways you can control workflows using Camunda Cloud — have a read of the others for some background if you’d like to see Camunda Cloud in action with Restzeebe, without a line of code:

Do you have to create or update screenshots of web products all the time? Do you find yourself thinking, “really, this again?” Welcome to the club! It takes me about 40 seconds per screenshot, so that’s almost seven minutes for 10 screenshots alone, just looking at the pure creation. So five iterations takes more than 30 minutes.

What if I told you that you could automate and standardize the whole process in 30 minutes with Camunda Cloud and Websiteshot? So you never have to go through the manual drudgery again!

Maybe it’s not immediately obvious why you would need this process. But there are some use cases that lend themselves to it:

  • Documentation: Screenshots are a visual extension of documentations that support or clarify a technical description. Especially in the environment of SaaS products, which have different views, screenshots are very helpful.
  • Evolution of products: If you wonder what your product looked like six months or two years ago, you probably wish you had taken screenshots from that time.
  • Visual fast-check after a release: Maybe you want to take a quick look at some (or all) views after a release. For this you can also use screenshots that give a snapshot of the latest views.

Here’s the scenario I’d like to walk you through in this tutorial:

  • A Camunda Cloud process orchestrates the screenshot generation.
  • We use Websiteshot to generate the screenshots. We use this SaaS because it’s quite easy to configure your URLs and the API is simple to use.
  • Finally, the finished screenshots are uploaded to an S3 bucket. Of course this can be exchanged with any other destination (Google Cloud Bucket, FTP server, Dropbox etc.).

So for this tutorial, you’ll need an account for Websiteshot and AWS. The free tier offerings are perfectly sufficient for what we have in mind 🙂

First iteration

Let’s start with the first iteration. This is the most minimal process that meets our requirements.

screenshot process

As you can see, the process consists of three simple steps that correspond to the scenario described above:

  1. Trigger screenshot job
  2. Wait 60 seconds for the screenshots to be generated (Websiteshot doesn’t offer webhooks yet, but it’s on the roadmap)
  3. Upload screenshots

Step 1 and 3 are service tasks, for each of which we again implement a simple worker. The second step is a timer event.

Let’s build the workers

We need workers that interact with two services. What simplifies things enormously: both Websiteshot and AWS offer Node.js SDKs that make integration very easy.

Create screenshots

The worker is quite simple, as the actual screenshot configuration takes place within Websiteshot. Templates can be created there, which contain the parameterization and all URLs.


So that the service task can be used quite flexibly, we pass the TemplateId to be used as a service task header. With this approach we don’t have to touch the worker if we want to use different templates.

export class WebsiteshotWorker {
  constructor(private zeebeController: ZeebeController) {}

  public create() {
      taskType: Worker.WEBSITESHOT_CREATE_JOB,
      taskHandler: async (job: any, complete: any, worker: any) => {
        const templateId = job.customHeaders.templateid;

        if (!templateId) {
          complete.failure('Template Id not set as header <templateid>');
        }`Creating Screenshot Job for Template Id ${templateId}`);

        const screenshotController = new ScreenshotController({
          projectId: ConfigController.get(
          apikey: ConfigController.get(ConfigParameter.WEBSITESHOT_API_KEY),

        try {
          const response = await screenshotController.create(templateId);
          complete.success({ jobId: response.jobId });
        } catch (error) {
          complete.failure('Failed to create screenshot job via websiteshot');

Websiteshot integration is not worth mentioning with the Library:

const response: CreateResponse = await this.websiteshotController.create({

Upload created screenshots

After the first worker has started the screenshot job, the second worker takes care of the next steps:

  • Fetch all created screenshots from Websiteshot.
  • Download the files temporarily
  • Upload the locally available files to S3

For this reason the worker is a bit more extensive:

export class BucketWorker {
  constructor(private zeebeController: ZeebeController) {}

  public create() {
      taskType: Worker.AWS_BUCKET_UPLOAD,
      taskHandler: async (job: any, complete: any, worker: any) => {
        const jobId = job.variables.jobId;
        if (!jobId) {
          complete.failure('Job Id not found on process context: <jobId>');

        const screenshotController = new ScreenshotController({
          projectId: ConfigController.get(
          apikey: ConfigController.get(ConfigParameter.WEBSITESHOT_API_KEY),

        const bucketController = new BucketController(
            id: ConfigController.get(ConfigParameter.AWS_SECRET_ID),
            secret: ConfigController.get(ConfigParameter.AWS_SECRET_KEY),

        try {
          const getResponse: GetResponse = await screenshotController.get(
          const files: Array<{
            url: string;
            name: string;
          }> = => {
            return {
              name: `${}.png`,
          files.forEach((file) =>`name: ${}`));
          const downloadPromises = =>
          await Promise.all(downloadPromises);

`Uploading Screenshots to Cloud Bucket`);

          const uploadPromises = =>
              Path.resolve(__dirname, `../..`, DOWNLOAD_FOLDER,,
          await Promise.all(uploadPromises);

          complete.success({ screenshots: uploadPromises.length });
        } catch (error) {
          complete.failure('Failed to send slack message');

Let’s take the Worker apart a bit.

Which job?

As a parameter, the worker gets the JobId from the process context. The first worker has written the JobId returned from Websiteshot to the process context at the end. Easy!

Which screenshots?

We are using the Websiteshot Node.js client again for this. Easy peasy.

Intermediate step

In order for us to upload the screenshots to the cloud bucket, we need to have them available. We take the easy way and save the screenshots temporarily before uploading them again. For this, we don’t need to do anything more than execute a few GET requests. In Node.js this is done with a few lines of code 🙂

Grand Finale

This is the central task of the worker. The previous three steps were just the preparation for this step. But even this part is pretty manageable with the help of the AWS SDK.

Yikes, are we done already? Yes! In fact, with this process and the associated workers, we’ve done everything we need to take screenshots of pre-configured URLs.

And now?

Now comes the concrete example: Camunda Cloud provides a console through which users can manage clusters and clients. Now I want to have screenshots taken from the Console using a test account. For this purpose I have created the following template:

template example

I use the process shown above exactly the same way to deploy and run it in Camunda Cloud. To start a new instance you can use Restzeebe. Once the workers are registered the service tasks are processed.

screenshot process in camunda cloud

The results can be viewed via the Websiteshot Console:

Websiteshot Console

And our screenshots end up in S3:

screenshots in s3

In the last few minutes we’ve built a process that automatically takes screenshots from the Cloud Console. URLs can be easily replaced, so we can create as many other templates as we want and just reuse the same process. All we need to do is adjust the header parameter. Pretty cool I think!

You can also view, fork and modify the complete implementation in this repo:

As with the last blog posts in this series: the process can easily be extended or the flow changed. For example, if you want to use the screenshots to automatically update the documentation, you can add an approval process. If you have read the tutorial with the Trello Cards you can, for example, create a new Trello Card on a specific board. A responsible person can then first look at the screenshots and either approve them for upload or reject them. In case of rejection, a specific message can be sent to a Slack channel because a view is not rendered correctly.

screenshot process with approval

Another nice use case is the automated generation of social share images of conference speakers — at a conference there are many speakers who like to be announced via social media. Here, a template based on HTML and CSS can be parameterized so that only the parameters need to be changed. A process could eventually generate the social share images and publish them to various social media platforms. Create the template once and sit back!

Maybe this tutorial has inspired you to automate the generation of your screenshots with the help of processes? If so, I look forward to your reports!

This blog was originally published on If you like this great tutorial, follow Adam on TwitterLinkedIn or GitHub 

  • Camunda Platform 8.1 Released – What’s New

    We’re extremely excited to announce the release of Camunda Platform 8.1.  In this post, we will go into the highlights of this release including Web Modeler, Connectors, Zeebe, Operate, Optimize, and more. Here’s the highlights of what’s included in this release: Easier Installation and maintenance for Camunda Platform Self-managed Hot backups for Self-Managed Token-Based authentication Modeler updates Process Templates FEEL Expression Editor Inline Annotations Changes to Camunda forms Connectors updates Workflow engine updates Operate updates Optimize updates Let’s get started! Easier installation and maintenance for Camunda Platform Self-Managed Improved Guides and Support for OpenShift and Amazon EKS (AWS) With this release, we are introducing official support for deploying and running Camunda Platform 8 Self-Managed on OpenShift and Amazon EKS (AWS)....

    Read more
  • Camunda Platform 7.18 Released – What’s New

    We’re extremely excited to announce the release of Camunda Platform 7.18 Here are some of the highlights: Cockpit: Improved instance selection to avoid unintended batch operations Cockpit: Easier navigation of high batch operation volumes MDC logging features Camunda Forms in Tasklist: Populate select options via process data Exception error codes Filter and order tasks by last updated WebSphere Liberty New and retired supported environments You can download Camunda Platform or run it with Docker. For a complete list of the changes, please check out the release notes. For patched security vulnerabilities, see our security notices. If you want to dig deeper, check out the source code on GitHub. Cockpit: Improved instance selection to avoid unintended batch operations Previously, when performing...

    Read more
  • Increase your resilience with new regions in...

    We’re excited to announce new regions for Camunda Platform 8 SaaS that further strengthen the resilience, performance, and data requirements for our SaaS customers. Enterprise customers can now choose to create their clusters in a number of regions including Europe West, US Central, US East, and the most recent addition, Australia South East. This provides multiple benefits, such as increasing availability, allowing to set up fail-safes, adhering to regulatory requirements for regional data storage, and reduced latency due to closer physical proximity. Resilience and redundancy in technology are important for all modern organizations and are top of mind for many. Across industries, organizations need a solution that scales effectively and is resilient to provide a good base for process orchestration....

    Read more

Ready to get started?

Still have questions?