{
  "slug": "html-comment-stripper",
  "name": "gizza-ai/html-comment-stripper",
  "version": "0.1.0",
  "title": "Remove HTML Comments — Keep Conditional, SSI and Banner Comments — gizza.ai",
  "description": "Strip HTML comments from markup and change nothing else. Keeps IE conditional, SSI and licence-banner comments by default. Free, runs in your browser.",
  "tags": [
    "remove html comments",
    "html comment stripper",
    "strip comments from html",
    "delete html comments online",
    "remove comments keep conditional comments",
    "remove wordpress block comments",
    "clean html before deploy",
    "remove css comments in style block"
  ],
  "category": "developer",
  "urls": {
    "page": "https://gizza.ai/tools/html-comment-stripper/",
    "markdown": "https://gizza.ai/tools/html-comment-stripper/index.md",
    "descriptor": "https://gizza.ai/tools/html-comment-stripper/tool.json",
    "deep_link_example": "https://gizza.ai/tools/html-comment-stripper/?html=%3C%21--%21%20%28c%29%202026%20Example%20Ltd%20--%3E%0A%3Ch1%3EHello%3C%2Fh1%3E%0A%3C%21--%20internal%20note%3A%20swap%20the%20hero%20copy%20--%3E%0A%3Cp%3EShip%20it.%3C%2Fp%3E&keep_conditional=true&keep_ssi=true&keep_bang=true&pattern=%5E%5Cs%2A%2F%3Fwp%3A&pattern_mode=keep&remove_css_comments=true&blank_lines=keep&output=html"
  },
  "cli": "gizza tool html-comment-stripper \"<!--! (c) 2026 Example Ltd -->\n<h1>Hello</h1>\n<!-- internal note: swap the hero copy -->\n<p>Ship it.</p>\"",
  "tool": {
    "description": "Remove <!-- … --> comments from HTML while leaving every other byte exactly where it was — no whitespace collapsing, no tag or attribute rewriting, no re-indentation, unlike a minifier. The scanner is raw-text- and quote-aware, which is what a '<!--.*?-->' regex gets wrong: a '<!--' inside <script>, <style>, <textarea>, <title> or inside a quoted attribute value is not a comment, comments do not nest (the FIRST '-->' closes one), and an unterminated comment is reported as an error instead of truncating the document. Conditional ('<!--[if lt IE 9]> … <![endif]-->'), SSI ('<!--#include … -->') and bang/banner ('<!--! … -->') comments are recognized as kinds and KEPT by default via keep_conditional / keep_ssi / keep_bang. pattern is a regular expression over each comment's inner text: with pattern_mode 'keep' it protects matching comments, with 'only' it inverts the tool so ONLY matching comments are removed (for deleting CMS block markers such as wp: while keeping real notes). remove_css_comments additionally strips string-aware '/* … */' comments inside <style>; JavaScript comments are deliberately never touched. blank_lines is 'keep' (default, byte-exact), 'trim' (drop lines a removal emptied) or 'collapse' (also fold blank runs). output is 'html' (the cleaned markup), 'report' (a metric,value CSV of counts, per-kind breakdown and bytes saved) or 'comments' (a line,kind,action,comment CSV dry-run listing). Max 5,000,000 bytes. Runs entirely in the sandbox; nothing is uploaded.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "blank_lines": {
          "default": "keep",
          "description": "What to do with lines a removal left empty. 'keep' (default) changes no whitespace at all, so the output is byte-for-byte the input minus the comments. 'trim' drops lines that became blank because a comment was removed, while lines that were already blank in the input are preserved. 'collapse' does that and also folds runs of consecutive blank lines into a single one.",
          "enum": [
            "keep",
            "trim",
            "collapse"
          ],
          "type": "string"
        },
        "html": {
          "description": "The markup to clean, as text. The output is the input MINUS the comment bytes — nothing else is touched: no whitespace collapsing, no tag or attribute rewriting, no re-indentation. The scanner is raw-text- and quote-aware, so a '<!--' inside <script>, <style>, <textarea>, <title> or inside a quoted attribute value is not a comment; comments do not nest, so '<!-- a <!-- b --> c -->' ends at the FIRST '-->'; and an unterminated comment is an error rather than a silent truncation of the rest of the document. Max 5,000,000 bytes.",
          "type": "string"
        },
        "keep_bang": {
          "default": true,
          "description": "Keep bang (banner) comments — any comment whose text starts with '!', such as '<!--! (c) 2026 Example Ltd, MIT licence -->'. That marker is the industry convention for licence headers and other must-keep notices, so it is on by default; turn it off only when you know the banners are disposable.",
          "type": "boolean"
        },
        "keep_conditional": {
          "default": true,
          "description": "Keep Internet Explorer conditional comments — '<!--[if lt IE 9]> … <![endif]-->' and the downlevel-revealed split forms. On by default, because deleting them changes which stylesheets and scripts legacy browsers load; turn it off to strip IE fallbacks along with everything else.",
          "type": "boolean"
        },
        "keep_ssi": {
          "default": true,
          "description": "Keep server-side include directives — any comment whose text starts with '#', such as '<!--#include virtual=… -->' or '<!--#echo var=… -->'. On by default: these are instructions to the web server rather than notes, so removing them silently drops part of the rendered page.",
          "type": "boolean"
        },
        "output": {
          "default": "html",
          "description": "What to return: 'html' (default) is the cleaned markup; 'report' is a metric,value CSV with comments_found/removed/kept, a per-kind breakdown of what was removed, css_comments_removed, and bytes_before/after/saved plus percent_smaller; 'comments' is a line,kind,action,comment CSV listing every comment found with its 1-based line, its kind (plain, conditional, ssi or bang) and whether it was removed or kept — the dry run for checking a rule before trusting it on a real file.",
          "enum": [
            "html",
            "report",
            "comments"
          ],
          "type": "string"
        },
        "pattern": {
          "default": "",
          "description": "Optional Rust regular expression matched against each comment's INNER text — what sits between '<!--' and '-->', delimiters excluded. Blank (the default) disables it. Under pattern_mode 'keep' a match PROTECTS the comment from removal; under 'only' a match is the only thing removed. Character classes, alternation, groups, quantifiers and anchors all work; there are no backreferences or lookaround, which is what keeps matching linear-time.",
          "type": "string"
        },
        "pattern_mode": {
          "default": "keep",
          "description": "How 'pattern' is applied. 'keep' (default) treats it as a keep-list: a matching comment survives even when its kind would otherwise be removed. 'only' inverts the tool — ONLY matching comments are removed and every other comment is left alone, which is how you delete CMS block markers such as wp: or analytics placeholders without touching real notes. 'only' with a blank pattern is an error, since nothing would be removed.",
          "enum": [
            "keep",
            "only"
          ],
          "type": "string"
        },
        "remove_css_comments": {
          "default": false,
          "description": "Also strip '/* … */' comments from inside <style> blocks. Off by default, so a run is purely an HTML-comment operation. The CSS pass is string-aware: a '/*' inside a quoted CSS string such as content: … is left alone. Comments inside <script> are never touched — correct JavaScript comment removal needs a real lexer, because '//' can appear inside a string or a regex literal.",
          "type": "boolean"
        }
      },
      "required": [
        "html"
      ],
      "type": "object"
    }
  }
}