Resolving S7-1200 Webserver AWP JavaScript Tag Write Errors
The SIMATIC S7-1200 integrated web server allows HTML pages stored in a project-generated "www" data block to read and write PLC tags through Automation Web Programming (AWP) commands. A frequent engineering problem arises when developers try to construct AWP commands at runtime from JavaScript — for example, when capturing canvas mouse coordinates and pushing them into a global DB. The web server returns errors such as WebInt:PLCtag"Zmienne"wspolrzedne.x not found and the tag never updates, even though the HTML page loads, the JavaScript executes, and the project compiles without errors.
This reference documents the root cause of the failure, the correct AWP syntax, the limits of the S7-1200 web server, and the engineering solutions that work in current TIA Portal versions (V16, V17, V18, V19, V20).
1. Problem Description
A user HTML page hosted on the S7-1200 web server implements a freehand drawing canvas. Each mousemove event must push the cursor coordinates to two PLC real (or LReal) tags inside a global DB named Zmienne (Polish for "Variables") — wspolrzedne.x and wspolrzedne.y ("coordinates").
The JavaScript constructs strings that look like AWP commands and appends them to a hidden <div>:
// BROKEN — does not work
infox = "<!-- AWP_In_Variable Name='wspolrzednex' Use='"Zmienne"wspolrzedne.x'-->:=wspolrzednex:";
document.getElementById("PLC_COMMAND_DIV").innerHTML += infox;
The page loads, the drawing works, the script runs without console errors, and TIA Portal → Compile → Download to device succeeds. However, after regenerating the www blocks and downloading again, the CPU diagnostic buffer records:
WebInt:PLCtag"Zmienne"wspolrzedne.x not found
WebInt:PLCtag"Zmienne"wspolrzedne.y not found
Coordinate values never reach the PLC. The web page reads 0.0 on the next refresh.
2. Root Cause Analysis
The web server processes AWP commands only during the static HTML compilation step, when TIA Portal generates the www data blocks. Once the HTML is stored on the CPU, the runtime web server treats <!-- ... --> as a literal HTML comment, regardless of how it was inserted.
Three independent failures occur in the example code:
| Failure | Mechanism | Effect |
|---|---|---|
| Dynamic AWP injection | AWP commands are stripped from the generated www DBs; the runtime does not re-parse innerHTML as AWP directives. |
Tags are never registered with the web server. |
Malformed Use= path |
The fully qualified tag path must be "DB_Name"."Tag" with no extra dot-separated segment. '"Zmienne"wspolrzedne.x' is parsed as a path element that does not exist. |
Diagnostic buffer error: PLCtag"Zmienne"wspolrzedne.x not found. |
| Wrong command for writing |
:=variable: is the read substitution (writes from PLC to HTML). AWP_In_Variable is the declaration command placed in the HTML <head>. |
No inbound binding is established. |
3. AWP Command Reference
Use the following command set inside the HTML files of your "Webserver" project node. All commands appear as HTML comments — the browser ignores them, the TIA compiler interprets them.
| Command | Direction | Purpose | Location |
|---|---|---|---|
<!-- AWP_In_Variable Name='"DB"."Tag"' --> |
PLC ← Browser | Declares a writable tag (form input, hidden field) |
<head> or <body>
|
<!-- AWP_Out_Variable Name='"DB"."Tag"' --> |
PLC → Browser | Declares a readable tag |
<head> or <body>
|
<!-- AWP_Enum_Def Name='MyEnum' Values='0="Off",1="On"' --> |
n/a | Defines enum for drop-down lists | <head> |
<!-- AWP_Enum_Ref Name='MyEnum' Enum='MyEnum' --> |
n/a | References enum on a tag | With AWP_In_Variable |
<!-- AWP_Start_Fragment --> / <!-- AWP_End_Fragment -->
|
n/a | Delimits an HTML fragment for repeated use | Surrounding block |
:="DB"."Tag": |
PLC → Browser | Inline read substitution (writes value into HTML output) | Inside tag attribute or text |
:="DB"."Tag":= |
PLC ← Browser | URL/parameter write target for HTTP GET writes | Inside form action URL |
The fully qualified tag name must be enclosed in single quotes and the inner double quotes must be escaped or written as raw ":
<!-- AWP_In_Variable Name='"Zmienne"."wspolrzedne"."x"' -->
<!-- AWP_In_Variable Name='"Zmienne"."wspolrzedne"."y"' -->
For structured tags, the AWP path uses dot notation. The example '"Zmienne"wspolrzedne.x' is missing the dot between the DB name and the structure instance and the dot between structure instance and member.
4. Why JavaScript Cannot Build AWP Commands
The web server architecture is split into two phases:
-
Compile phase (TIA Portal): Scans the source HTML files for AWP comments. Builds a binding table that maps each tag to an offset in the generated
wwwdata block. The AWP commands themselves are then removed from the generated HTML before it is placed in the www DB. -
Runtime phase (CPU web server): Serves the static HTML. Substitutes read values for
:=tag:markers. Writes values received in form posts to the registered bindings. Never re-parses the page.
When JavaScript executes element.innerHTML += "<!-- AWP_In_Variable ... -->", the browser's DOM inserts a comment node, but the S7-1200 web server has no listener for DOM mutations — it shipped the page bytes at request time and has no further involvement. The comment exists only in the browser memory of the client.
Even document.createComment(...) fails for the same reason: it inserts a DOM Comment node, not a binding directive. The web server is not the DOM.
5. Working Solutions
5.1 Solution A — Static binding with HTML input controls
Bind the coordinates to hidden form fields updated by JavaScript. The form is submitted through an HTTP GET or POST to the same page. The AWP read-write syntax handles the values.
HTML (in your fragment file draw.htm):
<html>
<head>
<!-- AWP_In_Variable Name='"Zmienne"."wspolrzedne"."x"' -->
<!-- AWP_In_Variable Name='"Zmienne"."wspolrzedne"."y"' -->
<title>Coordinate Write</title>
</head>
<body>
<form id="coordForm" method="POST" action="">
<input type="hidden" name='"Zmienne"."wspolrzedne"."x"' id="xIn" value="0">
<input type="hidden" name='"Zmienne"."wspolrzedne"."y"' id="yIn" value="0">
<input type="submit" value="Push to PLC">
</form>
<canvas id="c" width="400" height="300" style="border:1px solid #000;"></canvas>
<div id="PLC_COMMAND_DIV"></div>
<script>
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var last = 0, Timefreq = 30;
var tool = { started: false };
canvas.addEventListener('mousedown', function(ev){ tool.started = true; ctx.beginPath(); ctx.moveTo(ev.offsetX, ev.offsetY); last = new Date().getTime(); });
canvas.addEventListener('mouseup', function(ev){ tool.started = false; });
canvas.addEventListener('mouseleave',function(ev){ tool.started = false; });
canvas.addEventListener('mousemove', function(ev){
if (!tool.started) return;
var now = new Date().getTime();
if (now - last < Timefreq) return;
last = now;
ctx.lineTo(ev.offsetX, ev.offsetY);
ctx.stroke();
// Update the hidden inputs only — DO NOT inject AWP commands
document.getElementById('xIn').value = ev.offsetX;
document.getElementById('yIn').value = ev.offsetY;
});
// Optional: throttle form auto-submit to send coordinates every N ms
setInterval(function(){
if (tool.started) document.getElementById('coordForm').submit();
}, 200);
</script>
</body>
</html>
PLC data block Zmienne:
DATA_BLOCK "Zmienne"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
NON_RETAIN
STRUCT
wspolrzedne : STRUCT
x : REAL; // browser → PLC
y : REAL; // browser → PLC
END_STRUCT;
END_STRUCT;
END_DATA_BLOCK
For S7-1200 web access you must disable optimized block access (or use only single-element tags placed in a non-optimized DB) so the AWP binding offset is computable. Mark { S7_Optimized_Access := 'FALSE' } in the DB attributes or uncheck "Optimized block access" in the DB properties.
5.2 Solution B — Manual GET request without form submit
Use XMLHttpRequest or fetch() to POST a form-encoded payload to the page URL. The web server accepts URL-encoded name=value pairs and writes them to AWP-bound tags.
function pushCoord(x, y) {
var body = '"Zmienne"."wspolrzedne"."x"=' + encodeURIComponent(x)
+ '&"Zmienne"."wspolrzedne"."y"=' + encodeURIComponent(y);
fetch('/draw.htm', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: body,
credentials: 'include'
}).catch(function(err){ console.error('AWP write failed', err); });
}
For a one-variable write (e.g. boolean or integer), the GET form is shorter and fits the read-write marker syntax:
<a href="draw.htm? :="Zmienne"."wspolrzedne"."x":=>Set X</a>
For numeric ranges, encode the value directly in the URL after :=:
fetch('draw.htm?' + encodeURIComponent(':="Zmienne"."wspolrzedne"."x"') + '=' + x);
5.3 Solution C — TIA Portal V16+ Web API
From TIA Portal V16 onward, an HTTPS-based Web API is available on the S7-1200 web server. The API exposes each tag as a REST resource, so JavaScript can use fetch() against JSON endpoints without any AWP HTML trickery.
Enable the API: CPU Properties → Web server → Permitted users / API. Define a user with the Web API permission. The default base URL is https://<CPU-IP>>/api/ (or http:// if you have not enabled HTTPS).
JavaScript example:
async function setCoord(x, y) {
const auth = btoa('webuser:webpassword');
const headers = { 'Content-Type': 'application/json', 'Authorization': 'Basic ' + auth };
await fetch('https://192.168.0.10/api/v1/tags/Zmienne.wspolrzedne.x', {
method: 'PATCH',
headers: headers,
body: JSON.stringify({ value: x })
});
await fetch('https://192.168.0.10/api/v1/tags/Zmienne.wspolrzedne.y', {
method: 'PATCH',
headers: headers,
body: JSON.stringify({ value: y })
});
}
Endpoints (firmware V4.5 / TIA V17+):
| Method | URL | Effect |
|---|---|---|
| GET | /api/v1/tags/{path} |
Read single tag (JSON) |
| GET | /api/v1/tags?path={a}&path={b} |
Read multiple tags |
| PATCH |
/api/v1/tags/{path} with body {"value": n}
|
Write single tag |
| POST |
/api/v1/tags with body listing paths/values |
Bulk write |
The tag path uses dot notation: Zmienne.wspolrzedne.x (no DB quotes). For structured tags you must address the leaf. Optimized access is fully supported by the Web API, unlike AWP.
6. Step-by-Step Verification Procedure
-
Verify DB accessibility. In the project tree, right-click
Zmienne→ Properties → Attributes → uncheck Optimized block access. Recompile. Confirm the offset column is populated in the DB editor. -
Validate AWP syntax. Open your
.htmfile in TIA Portal. Right-click → "Web server" → "Generate web DB". Any syntax error appears in the Inspector → Info tab. - Download the www DB. Connect to the CPU, right-click the S7-1200 → Download to device → Software (all). Confirm the message Web DB generated successfully.
-
Test the URL. In a browser, navigate to
http://<CPU-IP>>/draw.htm. Confirm the page loads and the canvas is visible. -
Inspect the diagnostic buffer. In TIA Portal: Online → Online & Diagnostics → Diagnostic buffer. Any
WebInt:PLCtag ... not foundentry points to a misspelled path. -
Watch a tag in the watch table. Add
"Zmienne"."wspolrzedne"."x"to a watch table. Move the mouse and trigger a form submit. The value should change in <1 s. -
Open the browser dev tools. Network tab → submit the form → inspect the POST body. It should contain
%22Zmienne%22.%22wspolrzedne%22.%22x%22=123(URL-encoded tag name = value).
7. Common Error Matrix
| Symptom | Cause | Fix |
|---|---|---|
WebInt:PLCtag"Zmienne"wspolrzedne.x not found |
Malformed Name or Use attribute in AWP |
Use Name='"Zmienne"."wspolrzedne"."x"' with quoted DB and structure segments |
| Page loads but values always zero | AWP comment inside JavaScript string, not static HTML | Move AWP into static <head>; use form inputs to carry values |
| Compile error Maximum size of web DB exceeded | More than 64 KB of www content | Split HTML into fragments, reduce static AWP bindings, or move to Web API |
| HTTP 401 on POST | Web server user administration enabled but no login | Disable protection, or send Authorization: Basic header with valid user |
| Browser shows page fine on PC, not on phone | HTTPS-only mode forced in CPU | Set Enable HTTPS in CPU web server properties or accept the certificate |
JavaScript fetch blocked by CORS |
Web API and page served from different origins or no CORS | Serve page from the CPU itself or use plain XHR; the CPU does not send CORS headers |
| Tags visible in Go online but AWP does not bind | DB has Optimized block access enabled | Disable optimization on the DB (or move tags to a non-optimized DB) |
8. Memory Budget and Performance Notes
The S7-1200 web server stores all HTML in a single DB generated by TIA. The 64 KB cap is shared across all fragment files. Each AWP-bound input adds roughly 50–120 bytes of metadata in the binding table. A typical HMI with 50 inputs, 30 read displays, and 3 fragment files lands near 12–18 KB. Approaches that work cleanly:
- Use a single page that loads fragment files via
fetch()— each fragment has its own binding scope but ships in the same DB. - For dense numeric arrays, write a single tag of type
ARRAY[0..99] OF REALand bind one fragment template that iterates with JavaScript. The array costs one AWP binding; the loop costs nothing. - For canvas-style high-rate data (mouse moves at 60 Hz), do not POST every frame — buffer and submit at 5–10 Hz to avoid saturating the web server task.
The S7-1200 web server runs as a low-priority background task. Heavy write traffic increases CPU load and can extend OB1 cycle time if the project is small. Web API requests are processed sequentially per connection.
9. Best Practices for Production Web HMIs
- Bind only what you need. Avoid binding the entire DB. Each binding consumes DB memory and compile time.
- Validate in the PLC. A bound input is a remote-control surface. Add range checks and use the Error-checking and Range-checking options in the user program as recommended in the Siemens web server manual.
- Use the Web API for new projects (TIA V16+). It removes the 64 KB limit, supports optimized DBs, and gives JSON responses that are easier to parse than AWP substitutions.
- Force HTTPS. Web server authentication credentials and tag values cross the network in cleartext without it.
- Disable the web server when not needed. CPU Properties → Web server → uncheck Enable web server. The feature is not free at runtime.
- Do not place AWP commands in JavaScript strings. They are not interpreted. Plan bindings statically at compile time.
- Use the official S7-1200 G2 webserver video as a refresher for the new G2 generation's user interface: SIMATIC S7-1200 G2 Webserver Guide.
10. Cross-Reference: AWP vs. Web API vs. OPC UA
| Feature | AWP (HTML) | Web API (REST/JSON) | OPC UA |
|---|---|---|---|
| Minimum firmware | V4.0 | V4.4 (S7-1200 V16+) | V4.4 |
| Optimized DBs supported | No (partial in V4.4) | Yes | Yes |
| Storage limit | 64 KB www DB | None (DB content only) | None |
| Read latency (LAN) | 10–50 ms | 20–80 ms | 10–30 ms |
| Authentication | CPU user administration (V4.4+) | Basic / Digest | Certificate / user token |
| Best for | Simple custom HMI in HTML/CSS | Modern SPA, dashboards, mobile | SCADA, IIoT, cross-vendor |
11. Diagnostic Buffer Entry Decoder
Web server errors land in the diagnostic buffer with category "WebInt". Common entries:
| Message text fragment | Meaning | Action |
|---|---|---|
PLCtag ... not found |
AWP path is not in the binding table | Check Name / Use quoting and DB accessibility |
Web DB too large |
www DB > 64 KB | Split fragments, remove unused AWP, move to Web API |
Authentication failed |
Wrong or missing CPU user | Configure user in CPU web server properties |
HTTP request malformed |
Form post missing application/x-www-form-urlencoded
|
Set Content-Type header in JavaScript |
Method not allowed |
Web API endpoint does not accept the verb | Use PATCH/GET/POST as listed in §5.3 |
12. Frequently Asked Questions
Why does my JavaScript-injected AWP_In_Variable not bind a PLC tag?
The S7-1200 web server parses AWP commands at compile time inside TIA Portal, not at runtime in the browser. AWP comments inserted via innerHTML or createComment() exist only in the browser DOM and are never seen by the web server. Declare all AWP commands as static comments in the HTML source files of the webserver project node.
What is the correct AWP_In_Variable syntax for a structured tag?
Use dot-separated quoted segments: <!-- AWP_In_Variable Name='"DB"."StructInstance"."Member"' -->. For example, Name='"Zmienne"."wspolrzedne"."x"'. The DB must have optimized access disabled for the binding to be resolved by older firmware.
Can I write to PLC tags from JavaScript without reloading the page?
Yes, use fetch() or XMLHttpRequest to POST a form-encoded body to the page URL with name=value pairs that match your AWP-bound input names, or use the TIA V16+ Web API with JSON PATCH requests to /api/v1/tags/{path}. Both approaches avoid a full page reload.
What is the maximum size of the S7-1200 webserver www DB?
64 KB across all HTML files, fragments, and AWP binding metadata. On S7-1200 G2 the cap is similar (varies by firmware; consult the CPU manual). For projects exceeding this, use the Web API or OPC UA instead of AWP.
Do I need to disable optimized block access for AWP bindings?
Yes, on classic S7-1200 firmware (V4.0–V4.3). Disable Optimized block access on the data block containing AWP-bound tags. From firmware V4.4 the Web API works with optimized blocks; AWP support for optimized blocks is partial and case-dependent.
How do I push high-frequency mouse coordinates from a canvas to the PLC?
Throttle the writes (5–10 Hz is realistic for the S7-1200 web server), and use a form submit or a Web API PATCH per coordinate pair. Avoid posting on every mousemove event — the web server task will saturate. Buffer coordinates on the client and submit in batches when needed.