Building an Enterprise Developer Portal with Zadig - General Iframe Integration Plugin

Building an Enterprise Developer Portal with Zadig - General Iframe Integration Plugin

This article is one of the "Zadig IDP Plugin Development in Practice" series.

It focuses on a common requirement when implementing an internal developer platform (IDP) in enterprises—how to seamlessly integrate existing systems into a unified platform. Taking the "General Iframe Integration Plugin" as an example, we will demonstrate how to quickly embed third-party systems using the Zadig plugin system, achieving unified access for R&D tools and eliminating frequent switching. This plugin supports advanced features such as permission control and secure sandboxing, and is suitable for integrating monitoring dashboards, documentation systems, project management, and other external systems.

We will also release plugins for monitoring alert viewers, project management panels, and other typical use cases. Stay tuned!

# Preview

Current features:

  • Embed any external web page
  • Complete iframe configuration options (basic settings, permission controls, security sandbox)
  • Browser permission settings (fullscreen, camera, microphone, geolocation, etc.)
  • Sandbox permission configuration for fine-grained security control
  • Localized configuration storage to automatically remember user settings

# Preparation

This plugin took about one day to develop, but you don’t have to repeat the process! Following this tutorial, you can quickly finish within an hour and immediately experience a unified entry point.

Prerequisite knowledge:

Version requirements:

  • Node.js v20.0+
  • Yarn v4.0+
  • Zadig v4.0+

First, install the Zadig IDP plugin development SDK and initialize the plugin scaffold following the prompts:

# Install zadig-plugin-cli globally
yarn global add zadig-plugin-cli-dev
# Verify installation
zadig-plugin --version
zadig-plugin --help
# Create a plugin (default type: Page)
zadig-plugin create iframe-zadig

Enter the directory and start the development server. By default, you will see a Hello Plugin page, which you can modify based on the scaffold.

cd iframe-zadig
zadig-plugin dev

# Core Code Highlights

# Entry and Route Registration (index.js)

When the plugin is mounted, it registers the main route and defines manifest metadata (identifier, name, route, type, etc.). This is generated by the SDK by default and can be used as is.

// Route registration (excerpt)
this.registerRoute({
  path: "/",
  component: WrappedComponent,
  meta: {
    title: "Iframe Zadig",
  },
});

// manifest (excerpt)
const manifest = {
  identifier: "iframe-zadig",
  name: "Iframe Zadig",
  version: "1.0.0",
  description: "General Iframe Integration Plugin",
  type: "page",
  route: "/iframe-zadig",
};

# Main Page Container (components/MainPage.vue)

  • Uses local storage to save iframe configurations (URL, permissions, sandbox, etc.)
  • Automatically pops up the config dialog upon first visit
  • Supports clicking config button to modify settings at any time
<template>
  <div class="iframe-plugin">
    <!-- Config Button -->
    <div v-if="hasConfig" class="config-button-wrapper">
      <el-button
        type="primary"
        icon="el-icon-setting"
        circle
        size="small"
        @click="openConfigDialog"
      ></el-button>
    </div>

    <!-- iframe content -->
    <iframe
      v-if="hasConfig"
      class="iframe-content"
      :src="iframeConfig.url"
      :title="iframeConfig.title"
      :name="iframeConfig.name"
      :allow="iframeConfig.permissions.join(' ')"
      :sandbox="iframeConfig.sandboxEnabled ? iframeConfig.sandboxPermissions.join(' ') : null"
      :referrerpolicy="iframeConfig.referrerpolicy"
      :loading="iframeConfig.loading"
      frameborder="0"
    ></iframe>

    <!-- Config Dialog -->
    <ConfigDialog
      :visible.sync="showConfigDialog"
      :config="iframeConfig"
      @save="handleConfigSave"
    />
  </div>
</template>
// Initialization Logic (excerpt)
initPlugin() {
  // Read iframe config from storage
  if (this.storage) {
    const savedConfig = this.storage.get('iframeConfig')
    if (savedConfig && savedConfig.url) {
      // Config exists, load it
      this.iframeConfig = savedConfig
      this.hasConfig = true
    } else {
      // No config, pop up config dialog
      this.showConfigDialog = true
    }
  }
}

// Save Config (excerpt)
handleConfigSave(newConfig) {
  this.iframeConfig = newConfig
  this.hasConfig = true
  if (this.storage) {
    this.storage.set('iframeConfig', newConfig)
  }
  this.$message.success('Config saved!')
}

# Config Dialog (components/ConfigDialog.vue)

Designed with tabs, divided into three configuration modules: Basic, Permissions, Security Sandbox

# 1. Basic Configuration Tab

<!-- Basic Configuration (excerpt) -->
<el-tab-pane label="Basic Settings" name="basic">
  <el-form :model="form" :rules="rules" ref="configForm">
    <el-form-item label="URL" prop="url">
      <el-input
        v-model="form.url"
        placeholder="Enter iframe address, e.g.: https://example.com"
      />
    </el-form-item>

    <el-form-item label="Title" prop="title">
      <el-input v-model="form.title" placeholder="Enter title" />
    </el-form-item>

    <el-form-item label="Loading Strategy">
      <el-select v-model="form.loading">
        <el-option label="Eager" value="eager"></el-option>
        <el-option label="Lazy" value="lazy"></el-option>
      </el-select>
    </el-form-item>

    <el-form-item label="Referrer Policy">
      <el-select v-model="form.referrerpolicy">
        <el-option
          label="no-referrer"
          value="no-referrer"
        ></el-option>
        <el-option
          label="no-referrer-when-downgrade"
          value="no-referrer-when-downgrade"
        ></el-option>
        <el-option label="origin" value="origin"></el-option>
        <el-option label="same-origin" value="same-origin"></el-option>
      </el-select>
    </el-form-item>
  </el-form>
</el-tab-pane>

# 2. Permissions Tab Use the allow attribute to control browser features the iframe can access

<!-- Permissions (excerpt) -->
<el-tab-pane label="Permissions" name="permissions">
  <el-form :model="form">
    <el-form-item label="Permission List">
      <el-checkbox-group v-model="form.permissions">
        <el-checkbox label="fullscreen">Fullscreen</el-checkbox>
        <el-checkbox label="autoplay">Autoplay</el-checkbox>
        <el-checkbox label="camera">Camera</el-checkbox>
        <el-checkbox label="microphone">Microphone</el-checkbox>
        <el-checkbox label="geolocation">Geolocation</el-checkbox>
        <el-checkbox label="clipboard-read">Clipboard Read</el-checkbox>
        <el-checkbox label="clipboard-write">Clipboard Write</el-checkbox>
        <el-checkbox label="payment">Payment</el-checkbox>
        <el-checkbox label="usb">USB</el-checkbox>
        <!-- More permissions... -->
      </el-checkbox-group>
    </el-form-item>
  </el-form>
</el-tab-pane>

# 3. Security Sandbox Tab

When enabled, the iframe starts with minimal permissions and requires explicit authorization.

<!-- Security Sandbox (excerpt) -->
<el-tab-pane label="Security Sandbox" name="sandbox">
  <el-form :model="form">
    <el-form-item label="Enable Sandbox">
      <el-switch v-model="form.sandboxEnabled"></el-switch>
    </el-form-item>

    <el-form-item label="Sandbox Permissions" v-if="form.sandboxEnabled">
      <el-checkbox-group v-model="form.sandboxPermissions">
        <el-checkbox label="allow-scripts">Allow Scripts</el-checkbox>
        <el-checkbox label="allow-same-origin">Allow Same Origin</el-checkbox>
        <el-checkbox label="allow-forms">Allow Forms</el-checkbox>
        <el-checkbox label="allow-popups">Allow Popups</el-checkbox>
        <el-checkbox label="allow-modals">Allow Modals</el-checkbox>
        <el-checkbox label="allow-downloads">Allow Downloads</el-checkbox>
        <!-- More sandbox permissions... -->
      </el-checkbox-group>
    </el-form-item>
  </el-form>
</el-tab-pane>

# Build & Test

Use zadig-plugin dev for real-time preview and hot reload.

Debugging suggestions:

  • Open browser developer tools and check Console and Network
  • If the page fails to display, check if the target site has set X-Frame-Options to forbid embedding
  • If sandbox is enabled, make sure to check both allow-scripts and allow-same-origin

After local debugging, you can build for production:

# Build for production
zadig-plugin build

When building finishes, plugin.js will be generated in the dist/ directory—this is the final artifact to upload to Zadig.

# Uploading and Publishing in Zadig

  1. Log in to Zadig → Go to "System Settings → Plugin Management"

  2. Click "New Plugin", and fill in:

    1. Plugin Name: Iframe Integration Plugin
    2. Plugin Type: Page
    3. Route Path: /iframe-zadig
    4. Plugin Description: Embed third-party systems into the Zadig platform
    5. Plugin Status: Enabled
    6. Upload build artifact: dist/plugin.js
  3. Go back to the main sidebar, click add page, select plugin type, then select the newly created plugin

# Demo: Configurations and Use Cases

# Scenario 1: Embed Grafana Monitoring Dashboard

  1. Open the plugin page and the config dialog will pop up automatically

  2. Fill in the "Basic Settings" tab:

    1. URL: https://grafana.example.com/d/dashboard-id
    2. Title: System Monitoring
    3. Loading Strategy: lazy
  3. In the "Permissions" tab, check:

    1. Fullscreen
  4. "Security Sandbox" stays off

  5. Click "Save" to view monitoring data within Zadig

# Scenario 2: Embed Feishu Docs

  1. Open the plugin page and the config dialog

  2. Fill in the "Basic Settings" tab:

    1. URL: https://wiki.example.com
    2. Title: Internal Documentation
  3. In the "Permissions" tab, check:

    1. Fullscreen
    2. Clipboard Read
    3. Clipboard Write
  4. Click "Save" to view Feishu Docs within Zadig

# FAQ & Solutions

# Q: Why does the iframe show blank or get refused?

A: Possible causes:

  • The target website sets X-Frame-Options: DENY or SAMEORIGIN
  • Sandbox is enabled but allow-scripts is not checked
  • The URL is incorrect or inaccessible

Solutions:

  1. Check the browser console for error messages
  2. Verify if the target site allows iframe embedding
  3. If using sandbox, make sure to check required permissions

# Q: How can I embed HTTP content into an HTTPS page?

A: Due to browser mixed content policy, embedding HTTP pages in HTTPS context is blocked.

Solutions:

  1. Upgrade the target system to HTTPS
  2. Use a reverse proxy to serve HTTP as HTTPS

# Q: How to use different iframe configs on multiple pages?

A: Currently, each plugin instance supports only one config. To embed several different systems, you can:

  1. Create multiple plugin instances (recommended)
  2. Modify the plugin code to support multiple configs
  3. Use navigation tabs in the same plugin to switch between different URLs

# Future Iterations

  • Multiple Configs: Support configuring multiple iframe sources and quickly switching via tabs, no repetitive config needed.
  • Dynamic URL Parameters: Allow variables (e.g. current user, project ID) in the URL for personalized display.
  • Quick Action Bar: Add frequently used buttons (refresh, fullscreen, open in new window) above the iframe for enhanced user experience.
  • Communication Bridge: Enable two-way communication between Zadig and the embedded page, supporting data and event interactions.

# 🔜 Conclusion & Upcoming Topics

With this example, you can quickly understand how to build a general iframe integration plugin in Zadig, integrating all kinds of third-party systems into a unified platform. Leveraging the flexibility of the Zadig IDP plugin system, you can rapidly build a unified R&D collaboration portal per your team's needs, reducing tool-switching and improving developer experience.

📦 The sample plugin in this article is open source

See more on GitHub 👉 koderover/zadig-idp-plugins (opens new window)

Next up in this series:

"How to Build a Prometheus + Alertmanager Plugin in Zadig" — creating a unified entrance across systems for integrated R&D collaboration and monitoring.

📌 Follow us for the latest updates and deep dives in the Zadig IDP practical series!

Background Image

作为一名软件工程师,我们一直给各行各业写软件提升效率,但是软件工程本身却是非常低效,为什么市面上没有一个工具可以让研发团队不这么累,还能更好、更快地满足大客户的交付需求?我们是否能够打造一个面向开发者的交付平台呢?我们开源打造 Zadig 正是去满足这个愿望。

—— Zadig 创始人 Landy