Le 28 novembre, l'armée française s'avance sur trois colonnes. La colonne de droite est commandée par Alexandre Camille Taponnier, celle de gauche par Jean-Jacques Ambert. Hoche marche au centre, mais les chemins sont trop mauvais et il perd beaucoup de temps.
C'est Taponnier qui entre le premier au contact de l'ennemi et remporte aussitôt quelques succès. Mais Ambert a eu beaucoup de mal à traverser la Lauter et se trouve, avec seulement 6 000 hommes face au corps de Friedrich Adolf von Kalckreuth bien supérieur en nombre. Menacé d'encerclement, il doit se replier et rejoindre les forces de Hoche, qui vient à son secours.
Le 29, l’armée française franchit la rivière. L’avant-garde de Dubois et Molitor est sévèrement accrochée devant le plateau d'Erlenbach. Ambert doit se porter à leur secours en contournant le plateau. Seule une forte batterie installée sur les hauteurs voisine en vient à bout.
Hoche reforme alors ses troupes sur le mont Otterberg. Attaquée par plusieurs escadrons français, l'aile gauche prussienne, qui semble pourtant isolée, résiste. La brigade Simon se perd en attaquant l'aile droite ennemie et ne rejoint la division Paillard qu’à la tombée du jour. Il est trop tard pour entreprendre une nouvelle attaque, et Ambert reçoit ordre de marcher toute la nuit pour rejoindre Hoche.
De son côté, Taponnier attaque Kaiserslautern, mais seul et devant une forte résistance, il est repoussé dans les bois. Lui aussi passe la nuit sur le qui-vive.
Au matin du 30, la canonnade fait rage des deux côtés. Hoche lance de nouvelles attaques. Sur la gauche, à la tête de quatre bataillons, Molitor manque de prendre le Buchberg, mais il est repoussé. À droite la division Huet à du mal à se maintenir. Au centre, les cavaleries des deux camps chargent tour à tour, à l'envi, sans ordre et sans but précis : toutes ces attaques sont bien désordonnées. Voyant ses flancs bien appuyés, Brunswick fait marcher ses lignes pour reprendre le Otterberg et Hoche ordonne finalement d'abandonner le combat.