The Anon Runtime SDK allows you to capture live user sessions and automate actions as the authenticated user.

Ultimately, you are free to use any automation library you’d like to automate actions on connected user sessions. Playwright is a popular choice for browser automation, and we’ve included a reference implementation below.

Getting Started

First, install the required dependencies:

npm install @anon/sdk-typescript playwright

Complete Automation Example

Here’s a complete example of automating a post on Instagram using Playwright:

import { AnonRuntime } from '@anon/sdk-typescript';

const anon = new AnonRuntime({
  apiKey: process.env.ANON_API_KEY
});

const action = async (page) => {
  await page.goto("https://instagram.com");

  // Wait for the create button to be visible and click it
  await page.waitForSelector('svg[aria-label="New post"]');
  await page.click('svg[aria-label="New post"]');
  
  // Wait for the Post button to appear and click it
  await page.waitForSelector('svg[aria-label="Post"]');
  await page.click('svg[aria-label="Post"]');
  await page.waitForTimeout(2000);

  // Click upload image
  await page.waitForSelector('button:has-text("Select from computer")');
  await page.click('button:has-text("Select from computer")');
  await page.waitForTimeout(2000);

  // Handle file upload using the downloaded image
  const fileInput = await page.$('input[type="file"]');
  await fileInput.setInputFiles({
    name: 'image.jpg',
    mimeType: 'image/jpeg',
    buffer: imageBuffer
  });
  await page.waitForTimeout(2000);

  // Click the Next button twice
  await page.waitForSelector('div[role="button"]:has-text("Next")');
  await page.click('div[role="button"]:has-text("Next")');
  await page.waitForTimeout(1000);
  await page.waitForSelector('div[role="button"]:has-text("Next")');
  await page.click('div[role="button"]:has-text("Next")');
  await page.waitForTimeout(2000);

  // Write a caption
  await page.fill('div[aria-label="Write a caption..."]', caption);

  // Click the Share button
  await page.waitForSelector('div[role="button"]:has-text("Share")');
  await page.click('div[role="button"]:has-text("Share")');
  await page.waitForTimeout(2000);
};

// Run the action
(async () => {
  const result = await anon.run({
    appUserId: 'user@example.com',
    apps: ['instagram'],
    action
  });
})();

Best Practices

General best practices for Playwright

Wait for Elements

Always wait for elements to be ready before interacting with them:

// Good ✅
await page.waitForSelector('#submit');
await page.click('#submit');

// Bad ❌
await page.click('#submit');

Handle Loading States

Account for dynamic content and loading states:

// Wait for specific element
await page.waitForSelector('.loaded-content');

// Wait for network idle
await page.waitForLoadState('networkidle');

// Wait for URL change
await page.waitForURL('/dashboard');

Error Handling

Implement proper error handling and timeouts:

try {
  await page.waitForSelector('#element', {
    timeout: 5000,
    state: 'visible'
  });
} catch (error) {
  throw new Error('Element not found: ' + error.message);
}

Debugging Tips

Set Timeouts

Set timeouts to help with debugging:

await anon.run({
  appUserId: 'user_123',
  apps: ['example'],
  action: async (page) => {
    // Slow down actions by 1000ms
    await page.setDefaultTimeout(1000);
    // ... your action code
  }
});

Screenshots

Take screenshots during automation:

await page.screenshot({
  path: 'screenshot.png',
  fullPage: true
});

Console Logs

Access browser console logs:

page.on('console', msg => {
  console.log(`Browser log: ${msg.text()}`);
});

Advanced Features

Custom Headers

Add custom headers to requests:

await page.setExtraHTTPHeaders({
  'User-Agent': 'Custom User Agent',
  'Accept-Language': 'en-US'
});

Network Interception

Monitor or modify network requests:

await page.route('**/*', route => {
  const request = route.request();
  console.log(`${request.method()} ${request.url()}`);
  route.continue();
});

File Downloads

Handle file downloads:

const downloadPromise = page.waitForEvent('download');
await page.click('#download-button');
const download = await downloadPromise;
await download.saveAs('./downloaded-file.pdf');

Next Steps