Take a Screenshot of an Indian Bank Statement Webpage with PHP Laravel Dusk
Use Laravel Dusk to capture a fictional Indian bank statement page as a full-page, element, or responsive screenshot, with setup, code, and fixes.
Use Laravel Dusk’s screenshot() method to save a screenshot of a statement page, or screenshotElement() to capture only the statement component. The example below assumes your Laravel app has an app-owned route such as /demo/statement populated with fictional data. Dusk saves screenshots under tests/Browser/screenshots. See the Laravel Dusk documentation for version-specific setup and API details.
Keep the example synthetic. There is no single Indian bank statement webpage layout, and real account and transaction details are sensitive. Use invented names, masked or fabricated account numbers, and made-up transactions; do not use a live customer’s banking session as a test fixture or sample image. RBI materials discuss customer-information confidentiality, and Indian Bank’s 2025 policy identifies account and transaction data as financial data. These are reasons to minimize data in development, not a complete legal analysis for every environment. See the RBI resources and Indian Bank policy resources.
1. Install and prepare Laravel Dusk
For a project that already uses Dusk, confirm its installed version and skip to the test. For a new setup, Laravel’s documented workflow is to install Chrome, add Dusk as a development dependency, and run its installer:
composer require laravel/dusk --dev
php artisan dusk:install
Dusk uses Chrome by default. The ChromeDriver must match the installed Chrome or Chromium version. Laravel documents these commands for driver setup:
php artisan dusk:chrome-driver --detect
# Or install the latest driver supported by the command:
php artisan dusk:chrome-driver
Use the detection option when you need to align the driver with the browser already installed in the test environment. Follow the instructions for your Laravel version if the command options differ. Selenium-compatible drivers are also possible, but the example here uses Dusk’s default Chrome setup.
Laravel’s current Dusk documentation notes that Pest 4 includes automated browser testing and recommends Pest for new projects. This guide keeps to Dusk because that is the requested workflow; check the current Laravel documentation when choosing a browser-testing approach for a new application.
2. Render a fictional statement page
Dusk captures what the browser renders. Make the target route part of your application, and give the statement a stable selector if you may want a cropped capture. For example, your view could contain:
<main id="statement">
<h1>Account statement</h1>
<p>Account holder: Sample Person</p>
<p>Account number: XXXX0000</p>
<table>
<thead>
<tr><th>Date</th><th>Description</th><th>Amount (INR)</th></tr>
</thead>
<tbody>
<tr><td>2025-01-05</td><td>Example deposit</td><td>₹1,250.00</td></tr>
<tr><td>2025-01-12</td><td>Example purchase</td><td>−₹320.00</td></tr>
</tbody>
</table>
</main>
The names, dates, balances, and transactions above are illustrative only. Adapt fields to your own app; they do not describe a standard required by Indian banks. Prefer fixtures or seeded test data that cannot be confused with real customer records.
3. Capture the page with Dusk
Place a browser test in the project’s Dusk test suite. This example visits the app-owned route, checks that the page rendered its heading, and takes a screenshot:
<?php
namespace Tests\Browser;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class StatementScreenshotTest extends DuskTestCase
{
public function test_statement_page_can_be_captured(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/demo/statement')
->assertSee('Account statement')
->screenshot('indian-bank-statement');
});
}
}
This is an illustrative test, not a claim that it has been run against your application. Adapt the namespace, test base class, route, and assertion to the structure and conventions of your Laravel version. The screenshot name is a basename; Dusk documents screenshot output in tests/Browser/screenshots.
Run the Dusk suite using the project command:
php artisan dusk
Check the screenshot directory after the browser test completes. If you only need the statement region and the page has a stable selector, use an element screenshot:
$browser->visit('/demo/statement')
->assertSee('Account statement')
->screenshotElement('#statement', 'statement');
4. Choose the screenshot scope
| Need | Dusk method | Use it when |
|---|---|---|
| Page screenshot | screenshot('name') |
You need the browser page as a whole for evidence or visual review. |
| Element screenshot | screenshotElement('#statement', 'name') |
You want a focused capture of the statement component, without surrounding navigation. |
| Responsive screenshots | responsiveScreenshots('name') |
You want the documented responsive capture workflow for checking multiple viewport layouts. |
Use full-page capture when context such as the app shell matters. Capture the element when the statement itself is the review target. Use responsive captures when the layout changes with viewport size. Dusk documents these screenshot methods; consult its current docs for exact behavior in your installed version.
5. Make the capture stable
- Wait for asynchronous content. If rows are rendered by JavaScript, wait for a stable selector or visible text before capturing. A screenshot taken immediately after navigation can show a loading state.
- Make the viewport consistent. Set the browser size in the test when comparisons depend on identical dimensions. Dusk supports browser interaction and resizing; verify the method for your installed version.
- Use deterministic data. Fix dates, amounts, sorting, and locale in fixtures so unrelated changes do not alter the image.
- Control external dependencies. Avoid requiring a live bank login or a third-party service to render a test page. A local app-owned fixture is easier to repeat and safer to share.
- Keep visual content in view. If lazy-loaded rows or images are below the fold, ensure the app has rendered the intended content before capture and choose an appropriate page or element scope.
6. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| ChromeDriver fails to start or reports a version mismatch | The driver and installed Chrome/Chromium versions do not match. | Check the installed browser version, then use php artisan dusk:chrome-driver --detect as documented by Laravel. Confirm the browser is available in the test environment. |
| No screenshot appears | The test failed before reaching the screenshot call, or the file is being sought in the wrong directory. | Read the Dusk test output and inspect tests/Browser/screenshots. Confirm the route and assertion succeed before capture. |
| The screenshot is blank or shows a loading state | The route did not render the expected data, or JavaScript content had not finished loading. | Open the app-owned route in the test environment, confirm fixture data is present, and wait for a specific heading or statement selector before capturing. |
| The element capture fails or is empty | The selector is missing, unstable, or targets an element with no rendered size. | Inspect the rendered page and use a stable selector such as #statement. Assert that expected content is visible before calling screenshotElement(). |
| Images differ between runs | Viewport, locale, dates, data order, or asynchronous rendering varies. | Use fixed fixture values, consistent viewport settings, and an explicit wait for the final state. Avoid relying on live data. |
| Responsive captures look unexpected | The page’s responsive breakpoints or content differ from assumptions. | Inspect each captured viewport, verify CSS breakpoints and overflow behavior, and ensure the test data fits both narrow and wide layouts. |
| Currency symbols or dates render differently | Fonts, locale, or browser environment differ from the developer machine. | Make locale and fonts available in the browser environment and use deterministic formatting in the app fixture. |
7. Privacy, reliability, performance, and cost
Privacy: A screenshot is a copy of the visible page. Use fictional data, restrict access to generated artifacts, and apply the same retention and handling practices you use for other test outputs. Do not assume masking an account number makes real transaction details safe to publish.
Reliability: Dusk relies on a browser and compatible driver, so browser installation and version alignment are part of the test environment. An app-owned fixture route avoids dependence on a bank’s login flow, network, or changing page design. Keep assertions focused on content needed before the capture.
Performance: Browser startup and page rendering dominate a small screenshot test. Reuse the suite’s normal Dusk setup, avoid unnecessary navigation and external requests, and wait for a meaningful rendered condition rather than an arbitrary long delay. Capturing an element can produce a more focused artifact, while a full-page capture may include more content to render and inspect.
Cost: Dusk is an open-source Laravel browser-testing workflow; operational costs come from running the app, browser, driver, and CI resources. This tutorial does not assign a dollar cost because it depends on your infrastructure.
Or skip the browser setup
If you need a screenshot of a publicly reachable page without maintaining a browser and driver, ScreenshotNeo is a website screenshot API and MCP server. Its API documentation describes the request options. For a fictional or public demo statement page, a basic one-call capture looks like this:
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com/demo/statement \
-o statement.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com/demo/statement"},
timeout=90,
)
open("statement.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com/demo/statement'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('statement.webp', bytes));
Use only a page you are authorized to capture, and never send a real customer’s authenticated statement page or credentials. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Does Dusk capture an actual Indian bank’s statement page?
Dusk captures the page your test visits. This guide uses an app-owned fictional page; it does not automate a bank login or imply that bank sites share a common layout.
Can I take a screenshot of just the transaction table?
Yes. Give the table or its containing element a stable CSS selector and pass it to screenshotElement().
Is this suitable for production customer evidence?
The example is designed for synthetic test data. If a workflow involves real financial records, assess access, consent, storage, and retention requirements for that system before creating or distributing screenshots.


