Issue with URL-Encoding in Postman Code Blocks

Issue with URL-Encoding in Postman Code Blocks

Hey Postman team,

I’ve noticed that when adding scripts to documentation or the visualizer in Postman, the code blocks are URL-encoded(e.g., spaces as %20, = as %3D) or Improper Escaping in Editors.

Please fix this ?

  • Code blocks should render as plain text, not URL-encoded.
  • Copy-paste should provide clean, ready-to-use scripts.

Workspace & Example

Here’s an example of the issue:

  1. Expandable Grid Table Visualizer Collection:
    Link to Postman Collection
  2. Workspace:
    Link to Postman Workspace



Hi @gladwingt. Welcome to the Postman Community! :postman_logo:

Have you tried toggling the text editor format from plain text?

Yes, I also tried using JavaScript instead of plain text, but the result was the same. Each time, I completely removed the previous code block and created a new one. I’ve tried every possible approach.

Can you copy and paste the text in the text editor here so I can try to reproduce this on my end?

Test Script: Paste this into the code block and save it. Initially, everything will appear fine, but after 30 minutes, the code will display as encoded.

const responseData = pm.response.json();

// Utility to flatten nested objects
function flattenObject(obj, parent = '', res = {}) {
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            let propName = parent ? `${parent}.${key}` : key;
            if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
                flattenObject(obj[key], propName, res);
            } else {
                res[propName] = obj[key];
            }
        }
    }
    return res;
}

// Function to generate the HTML table with nested arrays and objects
function generateTable(data) {
    if (!Array.isArray(data) && data !== null && data !== undefined) {
        data = [data];
    }

    let table = '<table border="1" cellspacing="0" cellpadding="5" class="mac-table full-width" style="table-layout: auto; width: 100%;">';
    table += '<thead><tr>';
    if (data.length > 0) {
        Object.keys(flattenObject(data[0] || {})).forEach(function (key) {
            table += `<th style="white-space: nowrap; padding: 10px; text-align: left; border-bottom: 1px solid #ddd;">${key}</th>`;
        });
    }
    table += '</tr></thead><tbody>';

    data.forEach(function (row) {
        table += '<tr>';
        Object.values(flattenObject(row)).forEach(function (value) {
            if (value === null || value === '' || value === undefined) {
                table += '<td style="padding: 10px; border-bottom: 1px solid #ddd;">null</td>';
            } else if (Array.isArray(value)) {
                table += `<td style="position: relative; padding: 10px; border-bottom: 1px solid #ddd;">`;
                if (value.length > 0) {
                    table += `<button class="expand-button mac-button" data-expanded="false">+</button>
                              <div class="nested-table full-width" style="display:none; margin-top: 10px; background: #fff; box-shadow: 0 4px 8px rgba(0,0,0,0.1); overflow: auto; max-height: 500px;">
                              ${generateTable(value)}</div>`;
                } else {
                    table += 'null';
                }
                table += '</td>';
            } else if (typeof value === 'object' && value !== null) {
                table += `<td style="padding: 10px; border-bottom: 1px solid #ddd;">${JSON.stringify(value)}</td>`;
            } else {
                table += `<td style="padding: 10px; border-bottom: 1px solid #ddd;">${value}</td>`;
            }
        });
        table += '</tr>';
    });
    table += '</tbody></table>';
    return table;
}

// Template with CSS and expanded search functionality
const template = `<!DOCTYPE html>
<html>
<head>
    <style>
        .mac-table {
            width: 100%;
            table-layout: auto;
            border-collapse: collapse;
        }
        .mac-table th, .mac-table td {
            padding: 10px;
            border-bottom: 1px solid #ddd;
            text-align: left;
        }
        .nested-table {
            display: none;
            margin-top: 10px;
            background: #fff;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            max-height: 500px;
            overflow: auto;
        }
        .expand-button {
            cursor: pointer;
            background-color: #f4f4f4;
            border: none;
            padding: 5px;
            font-size: 14px;
        }
        .search-box {
            margin-bottom: 10px;
            width: 100%;
            padding: 8px;
        }
    </style>
</head>
<body>
    <input type="text" id="search-input" class="search-box" placeholder="Search..." />
    <div id="response">
        {{{tableHtml}}}
    </div>
    <script>
        // Search functionality
        document.getElementById('search-input').addEventListener('input', function () {
            const filter = this.value.trim().toLowerCase();
            const rows = document.querySelectorAll('#response tbody tr');

            rows.forEach(row => {
                let rowText = row.textContent.toLowerCase();
                let matchFound = rowText.includes(filter);
                let nestedMatch = false;

                // Check for matches in nested tables
                row.querySelectorAll('.nested-table').forEach(nestedTable => {
                    const nestedText = nestedTable.textContent.toLowerCase();
                    if (nestedText.includes(filter)) {
                        nestedMatch = true;
                        nestedTable.style.display = 'block'; // Expand matching nested tables
                        const expandButton = nestedTable.previousElementSibling;
                        expandButton.setAttribute('data-expanded', 'true');
                    } else {
                        nestedTable.style.display = 'none';
                        const expandButton = nestedTable.previousElementSibling;
                        expandButton.setAttribute('data-expanded', 'false');
                    }
                });

                // Display row if a match is found in the row or nested table
                row.style.display = matchFound || nestedMatch || filter === '' ? '' : 'none';
            });
        });

        // Expand/collapse functionality for nested tables
        document.addEventListener('click', function (event) {
            if (event.target.classList.contains('expand-button')) {
                const button = event.target;
                const nestedTable = button.nextElementSibling;
                const expanded = button.getAttribute('data-expanded') === 'true';
                nestedTable.style.display = expanded ? 'none' : 'block';
                button.setAttribute('data-expanded', !expanded);
            }
        });
    </script>
</body>
</html>`;

// Render the HTML with the generated table and search input
pm.visualizer.set(template, { tableHtml: generateTable(responseData) });

1 Like

Thanks for sharing this, @gladwingt.

I was able to replicate this issue on my end, and I have filed this as a bug report on our issue tracker on Github here.

I will recommend that you watch that issue or subscribe to it’s notifications as you’ll be able to provide any additional context the team needs to fix this or be notified when it is fixed.

Thank you for reporting this in as much detail as you did.

Cheers!

1 Like

Thanks for the quick response and for filing the bug report. I’ll follow up on the issue on GitHub to stay updated and provide any additional context if needed.

Honestly, I had previously tried addressing this issue through email, but I struggled to figure out how to proceed. I was sent documentation links that left me more confused than before. I kept going back to them, trying to make sense of it all, but each attempt felt more futile than the last. Frustration set in, and I finally gave up, feeling completely stuck.

It was tough revisiting what I thought was well documented, only to find it encoded and inaccessible. At times, I worried that others in the community might think less of me, which made the process even more discouraging. I began to feel like the community might see me as nothing more than a joke or an amateur, just another beginner in the coding field. It was mentally draining, and for a while, I even thought about abandoning this completely. I convinced myself to remove the code block entirely, unsure if I’d ever find a solution.

This final attempt to seek help here in the Postman community has been a turning point. I’m truly grateful to finally understand and feel supported. Thank you—it really means a lot.

Cheers!
Gladwin GT

1 Like

Hi @gladwingt. I’m really glad to hear that you found the community forum helpful. Here is always a great place to ask any product related question or seek help from the broader Postman community.

We’re always eager to help unblock users, get their feedbacks, and provide product related help where needed, so always feel free to ask a question, seek support, or share something fun you’re working on.

Cheers!
Debo

1 Like

Hi Debo,

Thanks for the warm response! I truly appreciate the support and will definitely reach out if I need help or have any questions.

Cheers!
GT

1 Like