DEV Community

Edgar Moran
Edgar Moran

Posted on

I Built a Mobile App to Monitor MuleSoft Anypoint Platform Here's How It Works

cover

I Built a Mobile App to Monitor MuleSoft Anypoint Platform

Picture this. It's 11pm on a Saturday. Your phone buzzes. Slack alert. Something in production is throwing 500s. You drag yourself to the desk, open the laptop, wait for the VPN to connect, load up the Anypoint Platform console, hunt for the right environment, find the app, pull the logs. Fifteen minutes gone. The incident thread already has 40 messages and someone's asking "any update?"

I lived that too many times. So I decided to build something about it.


So What Exactly Is Muleye?

Muleye is a mobile app for iOS and Android that gives MuleSoft engineers real operational visibility into their Anypoint Platform, right from their phone.

I want to be clear about what it's not. It's not a status page. It's not a browser wrapped in a mobile shell. It's a proper monitoring tool, built with React Native and Expo, with native gestures, push notifications, and features shaped by the stuff integration engineers actually deal with at 2 AM.

I shipped it on the App Store and Google Play back in January 2026, and I've been iterating on it ever since.


The "Why" Behind It

I've been working with MuleSoft for years. The Anypoint Platform browser console is great when you're sitting at your desk with your laptop open. But the second you step away, whether you're on-call, traveling, stuck in a meeting, or just trying to eat dinner, you're completely in the dark.

There was no native mobile experience for Anypoint. The console isn't responsive. You can't tail logs from your phone. You can't quickly check on your apps while you're walking to a conference room.

That gap between "something broke" and "I know what's happening" was consistently 15 to 20 minutes. I wanted to get that down to about 30 seconds. That's really what started this whole thing.


What It Can Do

Live Application Monitoring

Home Page

The home screen gives you a real-time health snapshot across every app and environment in your org. You can tell in one glance whether everything's good or if something's off.

It works across CloudHub, CloudHub 2.0, Runtime Fabric, and hybrid runtimes, all in the same view. And if you manage multiple Anypoint organizations (most of us do), you can switch between them instantly from the sidebar without logging out.

Real-Time Log Streaming

realtime logs

You can tail application logs live from your phone. Filter by log level, search the stream, tap any entry to expand the full JSON payload.

This ended up being the feature people use most during incidents. Instead of asking a teammate to paste logs into a Slack thread, you just pull out your phone and watch them scroll by in real time.

Flow Map Visualization

Flow visualization

This one was honestly the most fun to build.

Here's what happens: Muleye downloads the deployed Mule application artifact, parses the raw XML, extracts every <flow> and <sub-flow> definition, resolves all the <flow-ref> connections between them, and renders an interactive SVG diagram. All of that happens on the device itself. No server involved.

The layout engine runs a BFS-based topological sort to figure out which flows depend on which, and arranges them left to right by dependency depth. Sub-flows show up in purple, HTTP-triggered flows in blue, scheduler flows in amber. You can immediately see how the pieces connect.

The diagram supports:

  • Pinch-to-zoom (0.3x to 3x) so you can handle dense flows
  • Pan to move around large diagrams
  • Double-tap to snap back to the default view
  • Fullscreen mode for when you really need the screen real estate
  • Component preview where each flow node shows up to 4 of its processors (connectors, transforms, etc.)

Here's a simplified look at how the graph gets built under the hood:

// Parse Mule XML and extract flow definitions
const extractFlowDefinitions = (content, filePath) => {
  const definitions = [];
  // Match <flow> and <sub-flow> tags
  while ((match = FLOW_OPEN_TAG.exec(content)) !== null) {
    const tagType = match[1]; // 'flow' or 'sub-flow'
    const name = match[2];
    definitions.push({
      id: sanitizeId(`${filePath}:${name}`),
      name,
      type: tagType === 'sub-flow' ? 'sub-flow' : 'flow',
      trigger: inferTrigger(body), // HTTP, Scheduler, Message, File, Flow
      components: extractComponents(body),
    });
  }
  return definitions;
};

// Build the directed graph
const buildMuleFlowGraph = (files) => {
  const nodes = [];
  const edges = [];
  const nodeByName = new Map();

  // Extract all flow definitions from XML files
  Object.entries(files).forEach(([filePath, content]) => {
    extractFlowDefinitions(content, filePath).forEach((def) => {
      nodes.push(def);
      nodeByName.set(def.name, def);
    });
  });

  // Resolve flow-ref edges
  nodes.forEach((node) => {
    extractReferencedFlows(node.body).forEach((targetName) => {
      const target = nodeByName.get(targetName);
      if (!target) return;
      edges.push({ id: `${node.id}->${target.id}`, from: node.id, to: target.id });
    });
  });

  return { nodes, edges };
};
Enter fullscreen mode Exit fullscreen mode

And the layout engine that arranges everything into columns:

const buildFlowLayout = (graph, viewportWidth) => {
  const adjacency = new Map();
  const indegree = new Map();

  // BFS to assign levels (columns) by dependency depth
  graph.edges.forEach((edge) => {
    adjacency.get(edge.from).push(edge.to);
    indegree.set(edge.to, (indegree.get(edge.to) || 0) + 1);
  });

  // Start with nodes that have no incoming edges
  const queue = [];
  indegree.forEach((value, key) => {
    if (value === 0) queue.push(key);
  });

  // BFS assigns each node to the deepest level it reaches
  while (queue.length) {
    const current = queue.shift();
    (adjacency.get(current) || []).forEach((next) => {
      levelById.set(next, Math.max(levelById.get(next), currentLevel + 1));
      if (indegree.get(next) === 0) queue.push(next);
    });
  }

  // Position nodes in a column grid
  // ... spacing, centering, edge routing
};
Enter fullscreen mode Exit fullscreen mode

The end result is a clean left-to-right flow diagram that fits on a phone screen and lets you trace the call chain without ever opening Anypoint Studio.

Push Notifications and Smart Alerts

notifications

The alert system runs health checks in the background and pushes notifications to your phone even when the app isn't in the foreground.

One thing I was really intentional about: no MuleSoft credentials ever touch my server. Here's how the flow works:

  1. The app detects issues locally (status changes, error spikes)
  2. It relays alert metadata to a Firebase Cloud Function
  3. The Cloud Function calls the Expo Push API
  4. APNs or FCM delivers the notification to your device

When you tap a notification, it deep-links you straight to the relevant screen. Could be the specific app, its logs, or the alert detail. No hunting around.

There's also a Daily Health Digest that runs as a scheduled Cloud Function. Every morning it sends a push summary of your org's application health, so you start the day knowing if anything needs your attention before you even open the app.

And a Bunch More

  • Performance Metrics - CPU, memory, and request charts per application
  • Application Command Center - a unified dashboard with topology view, scheduler management, and metric cards
  • API Manager - browse your APIs, view policies, check contracts
  • API Governance - conformance checking across your API portfolio
  • AnypointMQ Statistics - queue and exchange monitoring with message counts
  • Object Store Explorer - browse and search key-value data
  • Environment Comparison - side-by-side view of apps across environments
  • Multi-region - US, EU, and GOV MuleSoft clouds all supported

The Technical Stack

Layer Technology
Framework Expo SDK 54, React Native 0.81.5
Language JavaScript / TypeScript
JS Engine Hermes
Navigation React Navigation 7.x
HTTP Axios with interceptors for token refresh
Auth Firebase Auth + MuleSoft OAuth2 (PKCE)
Subscriptions RevenueCat
Push Expo Notifications + Firebase Cloud Functions
Charts react-native-chart-kit
Diagrams react-native-svg (flow maps + topology)
Gestures react-native-gesture-handler + Reanimated
Storage Expo SecureStore (tokens), AsyncStorage (prefs)

Authentication Was the Hardest Part

Getting mobile OAuth2 working against MuleSoft's Anypoint Platform was probably the single biggest technical challenge of the whole project.

Muleye uses what I call a dual authentication system:

  1. Firebase Auth handles user identity (email/password or Apple Sign In)
  2. MuleSoft OAuth2 with PKCE handles the actual platform access

The clever part (if I can say that about my own code) is that the OAuth2 token exchange runs through Firebase Cloud Functions. That means no Anypoint credentials ever live on my server. The mobile client holds its own tokens in Expo SecureStore, and the Axios interceptor automatically refreshes them when they expire.

User opens app
  -> Firebase Auth check
  -> Link Anypoint account (OAuth2 PKCE)
  -> Token exchange via Firebase Functions
  -> Tokens stored in SecureStore
  -> Axios interceptor auto-refreshes on 401
Enter fullscreen mode Exit fullscreen mode

Multi-account support stores credentials per organization, so you can flip between your company's production org and your personal sandbox without having to log out and back in.

Each MuleSoft region (US, EU, GOV) has its own OAuth client ID and API endpoint. The Axios interceptor figures out the right base URL based on whichever account you have active before every request goes out.


Design: Make It Feel Native, Not Webby

From day one I wanted Muleye to feel like it belonged on your phone, not like a web app that got squeezed into a mobile container. That meant making a bunch of intentional choices:

  • Flat cards with hairline borders instead of heavy drop shadows
  • Grouped backgrounds following the iOS systemGroupedBackground pattern
  • Haptic feedback on tab switches, button taps, and quick actions
  • Native segmented controls with Reanimated sliding thumb animations
  • Dark mode that actually works, which required a full multi-wave theme migration across all 44 screens

The persistent tab bar at the bottom uses a graphite glass surface with blur on iOS, and every screen has its own native header rather than falling back on React Navigation's default chrome.

The small stuff matters more than you'd think. The flow map uses iOS-standard corner radii. Alert severity colors follow the iOS semantic palette. Pull-to-refresh tint tracks the active accent color. Individually these are tiny decisions, but together they're the difference between "this feels right" and "this feels off."


The Business Model

Muleye runs on a freemium model:

Free includes the home dashboard, application list, alert center, events feed, platform status, and hybrid infrastructure monitoring.

Premium unlocks real-time log streaming, performance metrics, flow maps, the command center, API management, AnypointMQ stats, and AI insights.

The paywall is powered by RevenueCat with monthly and annual options. When I first turned the paywall on, I gave every existing user a 30-day grace period with full access. Nobody lost features overnight. The conversion rate during that grace window ended up being solid, which told me the approach was right.


Things I Learned Along the Way

Ship the free version first. The core monitoring features like app status and alerts are useful enough on their own. Once people rely on the free tier every day, the premium features sell themselves.

Do the work on-device when you can. The flow map feature downloads the Mule artifact and parses XML entirely on the phone. No backend needed, no credentials exposed, instant results. The tradeoff is that really large apps with 30+ flows get dense on a phone screen, but pinch-to-zoom handles it, and it's still way faster than opening Studio.

Stop fighting the platform. Early versions of the app had custom gradients, heavy shadows, and what I'd call a "designed" look. Ripping all of that out and going with native iOS and Android patterns made the app feel dramatically better. It also cut the styling code roughly in half.

Push notifications are non-negotiable. The day I shipped push alerts, daily active usage jumped noticeably. People have their phone on them all the time. If you can tell someone something's wrong before their manager does, you've earned a permanent spot on their home screen.


What's Coming Next

  • Server-side monitoring so alerts work even when the app is fully closed
  • Expanded AI insights with anomaly detection and trend analysis
  • Deeper Runtime Fabric and hybrid runtime support
  • API analytics and traffic visualization

Give It a Try

Muleye is live on both platforms:

If you work with MuleSoft, I'd honestly love to hear what you think. This app was built by an integration engineer for integration engineers. Every feature started as a real frustration I had, and I'm always looking for the next one to solve.


Built by Edgar Moran - Sr Integration engineer, and someone who got really tired of opening a laptop at 11pm.

Top comments (0)