ScreenshotNeo

BlogHow-to

How to Detect Unauthorized Website Changes by Contractors

Learn how to define authorized work, trace website changes across your CMS and hosting stack, preserve evidence, and respond when an edit is unexpected.

By the ScreenshotNeo team4 October 202612 min read

A change log can help you find what changed, when it happened, and which account or system was involved. It cannot, by itself, prove which person was using that account or establish their intent. To investigate a contractor’s work reliably, define what is authorized, record activity in the CMS and outside it, preserve an approved baseline, and keep logs somewhere the monitored account cannot quietly alter.

If you are asking “How can I tell what a web developer changed on my website?” start by comparing the live site with the approved request and a known-good version. Then correlate CMS history with hosting, deployment, and identity logs. If the change was not approved, preserve evidence before making repairs.

1. Define what counts as authorized

Before granting access, write down the contractor’s named account, role, systems they may access, assigned tasks, approval contact, and expected work window. Use a separate account for each person. Shared administrator credentials make it harder to connect an event to an account and harder to revoke one person’s access cleanly.

Use the least privilege needed for the work. A content editor may not need plugin installation, user administration, hosting access, or database credentials. Review access when the project scope changes, and disable or remove it when the engagement ends. CMS access-control guidance provides a useful security model, though its formal requirements apply within its own scope rather than automatically to every private website. See the [CMS access-control guidance](https://www.cisa.gov/resources-tools/resources/securing-content-management-systems).

Agree on a change path: request, approval, implementation, review, and release. Record approved tasks and maintenance windows in a ticket or change register. For high-impact changes, use staging and require a named owner to approve promotion to production. Note automated jobs and scheduled updates too, so they are not mistaken for unexplained contractor activity.

2. Turn on CMS history and revisions

Enable the CMS’s native revisions and activity history where available. Record, at minimum, the event time and time zone, account and role, affected page or component, event type, result, and source address when available. Before-and-after values are especially useful for content, settings, and user-role changes.

For WordPress, keep revisions enabled and monitor changes, as recommended in the [WordPress hardening handbook](https://developer.wordpress.org/advanced-administration/security/hardening/). An activity-log plugin can supplement revisions. The [WP Activity Log listing](https://wordpress.org/plugins/wp-security-audit-log/) describes records for content, account, settings, plugin/theme, and file activity, with event details such as time, user/role, source IP, and affected object. The [Simple History listing](https://wordpress.org/plugins/simple-history/) describes a timeline, before-and-after content details, user changes, plugin events, and export options.

These are examples of vendor-maintained plugin listings, not guarantees of complete coverage or independent comparative tests. Verify current features, edition limits, retention, compatibility, and integration coverage for your WordPress version, page builder, plugins, REST/API routes, and deployment path. Logging only helps for events that the application or integration actually emits and retains.

WordPress setup checklist

  1. Create an individual account for the contractor and assign only the role needed for the approved tasks.
  2. Confirm that WordPress revisions are available for the content types the contractor will edit.
  3. Choose an activity-log plugin only after checking its current event coverage and storage/retention settings.
  4. In staging, perform representative actions: edit a page, change a user role, update a plugin, and use any page builder or API the contractor will use.
  5. Check that the expected events appear with useful timestamps, account details, affected objects, and before/after values where available.
  6. Configure alerts for high-impact events if the selected setup supports them, then make sure the right owner receives them.
  7. Export or mirror logs to storage controlled separately from the contractor’s and site administrator’s accounts where practical.

For example, WP Activity Log’s listing describes configurable retention and optional external storage or mirroring; check the installed edition and current settings rather than assuming those features are included. Simple History’s listing says its logs are stored in the WordPress database and can be exported. Database-resident logs are useful, but a person with sufficient database or administrator access may be able to change or remove them.

3. Monitor changes outside the CMS

A CMS activity log is only one part of the picture. A contractor may deploy through version control, edit files using SFTP or a hosting panel, change server configuration, update the database directly, or use an automated deployment account. A compromised account or scheduled process can also produce activity attributed to an account without proving who initiated it.

Correlate CMS history with whatever records your stack provides:

  • Code and deployments: version-control commits, pull requests, build records, deployment logs, and release identifiers.
  • Hosting and servers: control-panel activity, SSH/SFTP access, web-server logs, file changes, database activity, and configuration changes.
  • Identity and access: sign-ins, failed authentication, MFA events, role changes, API-token creation, and credential rotation.
  • Website files: integrity monitoring for additions, edits, and removals in important application and configuration paths.
  • Public pages: saved copies or periodic external captures of critical pages, compared with an approved version.

WordPress’s [hardening handbook](https://developer.wordpress.org/advanced-administration/security/hardening/) discusses file monitoring approaches including OSSEC and the inotify kernel event-monitoring service. Which approach fits depends on hosting access, operating system, and operational capacity. Use version control or a clean comparison copy for code and configuration; do not treat a public-page comparison as a substitute for those records.

An external page-change monitor or screenshot can show that the public appearance changed between captures. It may miss changes behind authentication, dynamic content, or pages it cannot access, and does not normally identify the account or person responsible. NARA’s [web-records guidance](https://www.archives.gov/records-mgmt/policy/managing-web-records.html) explains that snapshots can help track content changes and that the degree of reconstruction depends on whether referenced files are tracked too.

4. Compare against an approved baseline

A baseline is a known-good record of what the site looked like or contained at an approved point in time. It might include CMS revisions, a release tag, a backup, a database export, a file manifest, a deployment artifact, or a saved capture of important public pages. Keep the approval or release identifier with it so you know why that version was considered acceptable.

For each unexpected difference, record:

  • the object or URL and the time range when the difference first appeared;
  • the current value and the approved or previous value;
  • the related change request, ticket, release, or maintenance window, if any;
  • which account or automation appears in each relevant log;
  • what those systems do not record or what evidence is missing.

Compare like with like. Dynamic dates, rotating promotions, personalized content, cache state, and third-party widgets can change a page without a contractor editing its source. A screenshot is a visual record at one moment, not a complete copy of the site’s files, database, or configuration.

5. Protect logs and set a review routine

Decide before an incident how long logs and baselines need to be kept and who reviews them. Retention should reflect your site’s risk, investigation needs, storage capacity, and any legal or business requirements that apply. Review privileged-action alerts promptly and examine activity around releases and contractor offboarding.

Where practical, export or mirror records to a destination controlled separately from the accounts being monitored. Limit who can edit or delete that copy. Record the time zone and preserve original timestamps; when correlating systems, account for clock differences. NARA’s federal web-records guidance says site procedures should identify authorized creators, protect records against unauthorized addition, deletion, or alteration, and document site changes. Its scope is federal records guidance, but the record-integrity principles are useful to website owners generally.

6. Investigate and respond to a suspicious change

  1. Preserve first. Save relevant log entries, screenshots or captures, revisions, deployment records, and timestamps. Export logs before changing or restoring the affected system where possible.
  2. Compare the change. Identify the affected content, files, settings, or account and compare them with the approved request and known-good baseline.
  3. Correlate events. Check CMS, hosting, identity, deployment, and authentication history for the same time window. Look for scheduled updates or automated processes that could explain the event.
  4. Verify context. Contact the contractor through the agreed channel and ask whether the change was part of the work. Treat an account record as a lead, not proof of a person’s identity or intent.
  5. Contain if needed. If the change is harmful or access may be compromised, restrict or revoke the affected account, disable exposed tokens, and rotate credentials that may be at risk.
  6. Recover carefully. Restore from a known-good backup or redeploy a verified release when appropriate. Preserve the changed version first if it may be needed for investigation.
  7. Document and improve. Record evidence preserved, decisions, actions, and follow-up changes to permissions, approvals, backups, and monitoring. Bring in qualified incident-response help if the impact exceeds your team’s capability.

This sequence is a practical investigation workflow synthesized from audit and integrity guidance; it is not a claim that one authority prescribes this exact procedure. The [WordPress hardening handbook](https://developer.wordpress.org/advanced-administration/security/hardening/) notes that incidents can leave traces in logs or the file system, while NARA emphasizes protecting and documenting web records.

7. Select tools by coverage, not promises

Before depending on a CMS plugin, file monitor, or change service, check the specific routes your contractor uses. Ask whether it covers:

  • content editor, page builder, theme, plugins, settings, roles, REST/API activity, and deployment system;
  • timestamp, account, affected object, source, outcome, and before/after values;
  • alert speed for privileged actions or unexpected file/page changes;
  • export, retention, and a copy outside the website’s administrative control;
  • whether a monitored user can disable, alter, or delete the records;
  • compatibility, privacy, storage, maintenance, and cost implications.

Do not assume a plugin records every possible action. Confirm coverage in a staging environment or against current event documentation. The [WP Activity Log](https://wordpress.org/plugins/wp-security-audit-log/) and [Simple History](https://wordpress.org/plugins/simple-history/) directories describe their respective WordPress features; verify the current listing and installed configuration before relying on a feature.

Or skip the browser setup

For a repeatable visual record of an important public page, you can capture it directly with [ScreenshotNeo](https://screenshotneo.com), a website screenshot API and MCP server. A screenshot can help compare visible page states, but it does not identify who made a change or replace CMS, hosting, deployment, or identity logs. See the [ScreenshotNeo API documentation](https://screenshotneo.com/docs/).

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/important-page -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com/important-page"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com/important-page',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

Replace the example URL and API key with your page and key. For stable comparisons, capture the same URL with consistent options and timing, and store the resulting files with the date, release, and approval record. ScreenshotNeo removes cookie/consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

ScreenshotNeo includes full-page capture with lazy images loaded, CSS-selector element capture, device and viewport settings, dark mode, retina scale, PDF output, custom CSS and JavaScript, selector waits, delay and network-idle waits, request/resource blocking, custom headers and cookies, caching with a chosen TTL, and more. Those options can help make repeat captures consistent; consult the [docs](https://screenshotneo.com/docs/) for parameter names and behavior. One GET request returns PNG, JPEG, WebP, or PDF. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000, with every feature on every plan.

Start free with 1,000 screenshots a month and no card.

Performance, reliability, and cost

  • Capture cadence: capture high-impact pages around approved releases and at a cadence that matches how often they change and the consequences of missing a change. More frequent captures create more files and comparisons to review.
  • Dynamic pages: use consistent waits and capture settings. A page that has not finished loading, personalized content, or third-party scripts can create noisy differences. Record the capture time and relevant options.
  • Evidence reliability: a screenshot is one view of one URL at one moment. It does not preserve server files, database state, hidden content, or identity history. Pair it with revisions, deployment artifacts, backups, and protected logs.
  • Log reliability: logs can be incomplete, retained briefly, or controlled by the same privileged account under review. Test expected events and keep an independently controlled copy when practical.
  • Operating cost: CMS logging and file monitoring add storage, review, compatibility, and maintenance work. External monitoring or incident response may add service costs; compare them with the time and impact involved in investigating an unexplained change. ScreenshotNeo’s published plans are Free (1,000/month), Starter ($5/3,000), Growth ($15/15,000), Pro ($39/60,000), Scale ($99/250,000), and Business ($249/1,000,000); yearly billing gives two months free.

Troubleshooting

Symptom Likely cause What to do
No activity appears for a known edit The CMS, plugin, page builder, API route, or deployment method does not emit a covered event; logging may have been disabled. Reproduce the same action in staging, inspect current event coverage and settings, and add or enable logging at the system where the action occurs.
The log shows a contractor account, but they deny making the change Account attribution does not establish the human actor; a shared credential, stolen session, token, or automation may be involved. Preserve sign-in and token records, check source and related events, revoke suspect sessions or credentials if warranted, and verify context before assigning responsibility.
A visible page changed but CMS revisions are unchanged The change may come from theme/plugin code, a deployment, database or server change, cache, personalization, or third-party content. Compare file and deployment records, hosting logs, rendered captures, and cache state for the same time window.
A screenshot comparison reports many irrelevant differences Dynamic dates, rotating content, personalization, animation, fonts, or cookie state changed between captures. Use consistent capture conditions and waits, identify dynamic regions, and compare a stable page or element. Keep the original captures as evidence.
Logs are missing older events Retention may be short, storage limited, or logs may have been cleared. Check retention and export settings, establish a retention period suited to investigation needs, and mirror future logs to separately controlled storage.
An unexpected change aligns with a scheduled update An automated update or deployment may have produced the event. Check release, scheduler, and hosting records, and record recurring maintenance windows in the approved change register.
Restoring a backup removes useful investigation evidence Recovery was started before preserving the affected state and logs. When safe to do so, export logs and capture the changed files/content before recovery; then restore a verified known-good version.

FAQ

Can a website log prove a contractor made a change?

No. It can show that an account or system recorded an event. It does not prove who controlled the account at that moment or why the event occurred. Correlate records and ask for context.

How do I track changes made by a contractor in WordPress?

Use individual accounts, retain revisions, enable an activity history whose event coverage fits your setup, and check hosting and deployment records for work outside WordPress. Test the actions the contractor will use.

How can I tell if someone changed my website without permission?

Compare the current site and system state with an approved request and known-good baseline, then investigate the matching time window across CMS, hosting, identity, and deployment logs. An unexplained difference is a reason to investigate, not proof of a particular person’s intent.

Will a screenshot show who edited a page?

No. It records visible page output at capture time. Use account and system logs to investigate attribution.

What should I do before removing a contractor’s access?

Preserve relevant records, identify any shared credentials or tokens, and then revoke the contractor’s individual access when the engagement or approved scope ends. Rotate shared secrets if they may have been exposed.

How often should I review activity?

Review high-impact alerts promptly and inspect activity around releases and offboarding. Set the broader cadence based on how often the site changes and the consequences of an undetected change.